package cn.com.chengmandian.bike.service.impl;

import cn.com.chengmandian.agent.utils.AuthUtil;
import cn.com.chengmandian.bike.constants.BikeConstants;
import cn.com.chengmandian.bike.dto.MemberLocationDisptachForm;
import cn.com.chengmandian.bike.dto.MemberLocationForm;
import cn.com.chengmandian.bike.dto.RideOrderDto;
import cn.com.chengmandian.bike.dto.RideOrderForm;
import cn.com.chengmandian.bike.model.*;
import cn.com.chengmandian.bike.mapper.EbRideOrderMapper;
import cn.com.chengmandian.bike.model.vo.*;
import cn.com.chengmandian.bike.service.*;
import cn.com.chengmandian.bike.utils.AliPayUtil;
import cn.com.chengmandian.bike.utils.OrderPriceUtil;
import cn.com.chengmandian.bike.utils.WxPayUtil;
import cn.com.chengmandian.core.common.constants.CommonConstant;
import cn.com.chengmandian.core.common.utils.BillNoUtil;
import cn.com.chengmandian.core.redis.cache.AgentParamCacheService;
import cn.com.chengmandian.core.redis.cache.BikeSuperviseCacheService;
import cn.com.chengmandian.core.redis.service.RedisService;
import cn.com.chengmandian.core.web.exceptions.BadResponseException;
import cn.com.chengmandian.core.web.pojo.*;
import cn.com.chengmandian.core.web.service.OssService;
import cn.com.chengmandian.core.web.utils.LocalMapUtil;
import cn.com.chengmandian.core.web.utils.SpringContextUtil;
import cn.com.chengmandian.rabbitmq.event.BikeEventCode;
import cn.com.chengmandian.rabbitmq.event.EventService;
import cn.com.chengmandian.service.bike.BikeCenterClient;
import cn.com.chengmandian.service.bike.BikeCommonClient;
import cn.com.chengmandian.service.bike.BikePayClient;
import cn.com.chengmandian.service.bike.IotBikeClient;
import cn.com.chengmandian.service.bike.constants.*;
import cn.com.chengmandian.service.bike.form.*;
import cn.com.chengmandian.service.bike.pojo.CloseLockRequest;
import cn.com.chengmandian.service.bike.pojo.Gps;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.*;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 电单车运营-骑行订单 服务实现类
 * </p>
 *
 * @author AutoGenerator
 * @since 2021-12-10
 */
@Slf4j
@Service
public class EbRideOrderServiceImpl extends ServiceImpl<EbRideOrderMapper, EbRideOrder> implements IEbRideOrderService {
    @Autowired
    private RedisService redisService;

    @Autowired
    private IEbMemberInfoService memberInfoService;

    @Autowired
    private IEbDeviceBikeService deviceBikeService;

    @Autowired
    private IEbPriceRuleService priceRuleService;

    @Autowired
    private IEbMemberWalletService memberWalletService;

    @Autowired
    private IEbRideCommandService rideCommandService;

    @Autowired
    private IotBikeClient iotBikeClient;

    @Autowired
    private IEbMemberCardService memberCardService;

    @Autowired
    private EbRideOrderMapper rideOrderMapper;

    @Autowired
    private IEbMemberCouponService memberCouponService;

    @Autowired
    private IEbRideOrderService rideOrderService;

    @Autowired
    private IEbDevicePathService devicePathService;

    @Autowired
    private IEbMemberPayService memberPayService;

    @Autowired
    private AgentParamCacheService agentParamCacheService;

    @Autowired
    private IEbMessageInfoService messageInfoService;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private IEbRefundInfoService refundInfoService;

    @Autowired
    private IEbOperationStationService operationStationService;

    @Autowired
    private IEbRideModifyService rideModifyService;

    @Autowired
    private IEbRentOrderService rentOrderService;

    @Autowired
    private BikeCenterClient bikeCenterClient;

    @Autowired
    private BikeSuperviseCacheService superviseCacheService;

    @Autowired
    private IEbCommonParamService paramService;

    @Autowired
    private IEbPreOrderService preOrderService;

    @Autowired
    private IEbRidePenaltyService ridePenaltyService;

    @Autowired
    private IEbRemindRuleService remindRuleService;

    @Autowired
    private BikeCommonClient commonClient;

    @Autowired
    private IEbCardInfoService cardInfoService;

    @Autowired
    private IEbPriceStepService priceStepService;

    @Autowired
    private IEbAgentInfoService agentInfoService;

    @Autowired
    private IEbPayAccountService payAccountService;

    @Autowired
    private BikePayClient payClient;

    @Autowired
    private IEbRideDistanceService rideDistanceService;

    @Autowired
    private IEbPhotosStopService photosStopService;

    @Autowired
    private IEbRideHelmetService rideHelmetService;

    @Autowired
    private OssService ossService;

    @Autowired
    private IEbRideCloseService rideCloseService;

    @Autowired
    private EventService eventService;

    @Override
    public EbRideOrder getRideConfirmOrder(Integer memberId) {
        return this.getOne(new LambdaQueryWrapper<EbRideOrder>()
                .eq(EbRideOrder::getMemberId, memberId)
                .in(EbRideOrder::getStatus, RideOrderStatusEnum.RIDING.getCode(), RideOrderStatusEnum.PAUSE.getCode(), RideOrderStatusEnum.CONFIRM.getCode())
                .last("limit 0,1"));
    }

    @Override
    @Transactional
    public EbRideOrder addOrder(EbDeviceBike deviceBike, MemberLocationForm memberLocationForm, AgentUser agentUser) {
        String redisKey = "CMD:BIKE:ADDORDER:" + deviceBike.getBikeNo();
        Assert.isTrue(!redisService.hasKey(redisKey), "车辆使用中，请稍候");
        redisService.set(redisKey, true, 5);
        // 作废初始化订单
        this.failBikeInitOrder(deviceBike.getId(), agentUser.getId());

        EbRideOrder rideOrder = new EbRideOrder();
        rideOrder.setOrderNo(BillNoUtil.getSimpleNo("RO-"));

        EbPriceRule priceRule = priceRuleService.getRule(deviceBike.getAreaId());
        if (priceRule.getUserRidingNumber() > 0 && priceRule.getUserRidingMinute() > 0
            && this.count(new LambdaQueryWrapper<EbRideOrder>().eq(EbRideOrder::getMemberId, agentUser.getId())
                .eq(EbRideOrder::getAreaId, deviceBike.getAreaId())
                .notIn(EbRideOrder::getStatus, RideOrderStatusEnum.INIT.getCode(), RideOrderStatusEnum.FAIL.getCode())) < priceRule.getUserRidingNumber()) {
            // 租赁订单
            if(BikeConstants.isRent) {
                if(rentOrderService.count(new LambdaQueryWrapper<EbRentOrder>().eq(EbRentOrder::getAreaId, deviceBike.getAreaId()).eq(EbRentOrder::getMemberId, agentUser.getId())
                        .notIn(EbRentOrder::getStatus, RentOrderStatusEnum.BIKE.getCode()).ne(EbRentOrder::getIsRenew, CommonConstant.ONE)) < priceRule.getUserRidingNumber()) {
                    rideOrder.setIsNew(CommonConstant.ONE);
                }
            }
        } else {
            rideOrder.setIsNew(CommonConstant.ZERO);
        }
        rideOrder.setAreaId(deviceBike.getAreaId());
        rideOrder.setGirdId(deviceBike.getGirdId());
        rideOrder.setBikeNo(deviceBike.getBikeNo());
        rideOrder.setBikeId(deviceBike.getId());
        rideOrder.setMemberId(agentUser.getId());
        rideOrder.setStatus(RideOrderStatusEnum.INIT.getCode());
        rideOrder.setStartStationId(deviceBike.getStationId());
        rideOrder.setMemberStartLat(memberLocationForm.getLat());
        rideOrder.setMemberStartLng(memberLocationForm.getLng());
        rideOrder.setStartLat(deviceBike.getLat());
        rideOrder.setStartLng(deviceBike.getLng());
        rideOrder.setPenaltyPayStatus(CommonConstant.ONE);
        rideOrder.setCreateTime(new Date());
        this.save(rideOrder);

        return rideOrder;
    }

    @Override
    public void failBikeInitOrder(Integer bikeId, Integer memberId) {
        List<EbRideOrder> initList = baseMapper.getInitOrderList(bikeId, memberId);
        // 先拉取列表，再更新，防止死锁
        for(EbRideOrder order : initList) {
            this.update(new LambdaUpdateWrapper<EbRideOrder>()
                    .set(EbRideOrder::getStatus, RideOrderStatusEnum.FAIL.getCode())
                    .eq(EbRideOrder::getId, order.getId()));
        }
    }

    @Override
    public void failInitOrder(Integer orderId) {
        this.update(new LambdaUpdateWrapper<EbRideOrder>()
                .set(EbRideOrder::getStatus, RideOrderStatusEnum.FAIL.getCode())
                .eq(EbRideOrder::getId, orderId)
                .eq(EbRideOrder::getStatus, RideOrderStatusEnum.INIT.getCode()));
    }

    @Override
    public EbRideOrder getByNo(String orderNo, Integer memberId) {
        return this.getOne(new LambdaQueryWrapper<EbRideOrder>()
                .eq(EbRideOrder::getOrderNo, orderNo)
                .eq(EbRideOrder::getMemberId, memberId)
                .last("limit 1"));
    }

    /**
     * 车辆开锁
     */
    @Override
    public void openLock(String orderNo, Integer memberId) {
        EbRideOrder rideOrder = this.getByNo(orderNo, memberId);
        Assert.notNull(rideOrder, "订单不存在");

        // 订单骑行中
        Assert.isTrue(!rideOrder.getStatus().equals(RideOrderStatusEnum.RIDING.getCode()), "当前已是骑行中");

        // 订单未支付
        Assert.isTrue(!rideOrder.getStatus().equals(RideOrderStatusEnum.CONFIRM.getCode()), "订单已确认，请及时付款");

        // 订单已完成
        Assert.isTrue(!rideOrder.getStatus().equals(RideOrderStatusEnum.COMPLETE.getCode()), "当前订单已结束");

        String redisKey = "CMD:BIKE:ORDER:LOCK:" + orderNo;
        Assert.isTrue(!redisService.hasKey(redisKey), "请勿频繁操作");
        redisService.set(redisKey, true, 3);
        EbMemberInfo memberInfo = memberInfoService.getById(memberId);

        rideCommandService.addCommand(rideOrder, DeviceCommandEnum.OPEN_LOCK, UserTypeEnum.MEMBER.getCode(), memberId, memberInfo.getName());
    }

    /**
     * 临时停车
     */
    @Override
    public void memberStopLock(String orderNo, Integer memberId, Integer sendStopCommand) {
        EbRideOrder rideOrder = this.getByNo(orderNo, memberId);
        Assert.notNull(rideOrder, "订单不存在");
        EbMemberInfo memberInfo = memberInfoService.getById(memberId);

        // 临停次数限制
        BikeAreaParam bikeAreaParam = agentParamCacheService.getParam(rideOrder.getAgentId(), rideOrder.getAreaId());
        if(bikeAreaParam != null && bikeAreaParam.getUserRideStopBikeMaxTimesEnabled()) {
            if(bikeAreaParam.getUserRideStopBikeMaxTimes() <= 0) throw new BadResponseException("禁止临时停车");

            Integer stopLockTimes = rideCommandService.getCommandCount(rideOrder.getId(), DeviceCommandEnum.STOP_LOCK);
            if(stopLockTimes >= bikeAreaParam.getUserRideStopBikeMaxTimes()) {
                throw new BadResponseException("抱歉，临停次数已用完，请停车缴费");
            }
        }
        this.stopLock(rideOrder, false, UserTypeEnum.MEMBER.getCode(), memberId, memberInfo.getName(), sendStopCommand);
    }

    @Override
    public void sysStopLock(SysStopOrderForm sysStopOrderForm) {
        EbRideOrder rideOrder = this.getById(sysStopOrderForm.getOrderId());
        Assert.notNull(rideOrder, "订单不存在");
        this.stopLock(rideOrder, true, UserTypeEnum.SYS.getCode(), 0,
            StrUtil.isEmpty(sysStopOrderForm.getSysName()) ? "系统" : sysStopOrderForm.getSysName(),
            CommonConstant.ONE);
    }

    @Override
    public void openHelmet(String orderNo, Integer memberId) {
        EbRideOrder rideOrder = this.getByNo(orderNo, memberId);
        Assert.notNull(rideOrder, "订单不存在");

        Assert.isTrue(rideOrder.getStatus().equals(RideOrderStatusEnum.RIDING.getCode()) || rideOrder.getStatus().equals(RideOrderStatusEnum.PAUSE.getCode()), "订单状态不正确");

        EbDeviceBike deviceBike = deviceBikeService.getById(rideOrder.getBikeId());

        String redisKey = "CMD:BIKE:ORDER:HELMET:" + deviceBike.getId();
        Assert.isTrue(!redisService.hasKey(redisKey), "请勿频繁操作");
        redisService.set(redisKey, true, 3);

        SendBikeCommandForm commandForm = new SendBikeCommandForm()
                .setAgentId(LocalMapUtil.getAgentInfo().getId())
                .setBikeNo(deviceBike.getBikeNo())
                .setCommand(DeviceCommandEnum.OPEN_HELMET.getType())
                .setUserId(AuthUtil.getAgentUser().getId())
                .setUserName(AuthUtil.getAgentUser().getName())
                .setUserType(UserTypeEnum.MEMBER.getCode());
        AjaxResult res = iotBikeClient.sendBikeCommand(commandForm);
        if (!res.isSuccess()) {
            throw new BadResponseException("头盔锁打开失败：" + res.getMessage());
        }
    }

    @Override
    public EbRideOrder getByBike(Integer bikeId) {
        return this.getOne(new LambdaQueryWrapper<EbRideOrder>()
                .eq(EbRideOrder::getBikeId, bikeId)
                .in(EbRideOrder::getStatus, RideOrderStatusEnum.INIT.getCode(), RideOrderStatusEnum.RIDING.getCode(), RideOrderStatusEnum.PAUSE.getCode())
                .orderByDesc(EbRideOrder::getId)
                .last("limit 1"));
    }

    /**
     * 临时停车
     */
    @Override
    public void stopLock(EbRideOrder rideOrder, boolean superRole, Integer userType, Integer userId, String userName, Integer sendStopCommand) {

        if (rideOrder.getStatus().equals(RideOrderStatusEnum.COMPLETE.getCode())) {
            throw new BadResponseException("当前订单已结束");
        }

        if (rideOrder.getStatus().equals(RideOrderStatusEnum.CONFIRM.getCode())) {
            throw new BadResponseException("当前订单已进入确认状态");
        }

        EbDeviceBike deviceBike = deviceBikeService.getById(rideOrder.getBikeId());

        if (!superRole) {
            Assert.isTrue(deviceBike.getIsInArea().equals(CommonConstant.ONE), "当前不在服务区，无法临时锁车");
            Assert.isTrue(deviceBike.getNoparkingId() == null, "当前处于禁停区，无法临时锁车");
        }
        if(sendStopCommand == null || sendStopCommand.equals(CommonConstant.ONE)) {
            String redisKey = "CMD:BIKE:ORDER:LOCK:" + rideOrder.getOrderNo();
            Assert.isTrue(!redisService.hasKey(redisKey), "请勿频繁操作");
            redisService.set(redisKey, true, 3);
            rideCommandService.addCommand(rideOrder, DeviceCommandEnum.STOP_LOCK, userType, userId, userName);
            // 临时停车成功消息推送
            rideCommandService.orderStopCommandPush(rideOrder, userType);
        }
    }

    /**
     * 结束关锁
     */
    @Override
    @Transactional
    public void opsCloseLock(Integer orderId, Integer closeReason, Integer opsUserId, String userName, BigDecimal customMoney) {
        EbRideOrder rideOrder = this.getById(orderId);
        Assert.notNull(rideOrder, "订单不存在");
        this.closeLock(rideOrder, CommonConstant.ONE, CommonConstant.ONE, false, customMoney, true, UserTypeEnum.OPS.getCode(), opsUserId, userName);
        // 更新订单信息
        this.update(new LambdaUpdateWrapper<EbRideOrder>()
                .set(EbRideOrder::getOpsCloseReason, closeReason)
                .set(EbRideOrder::getOpsCloseUserId, opsUserId)
                .eq(EbRideOrder::getId, rideOrder.getId()));
    }

    /**
     * 结束关锁
     */
    @Override
    public void agentCloseLock(Integer orderId, BigDecimal customMoney, Integer userId, String userName) {
        EbRideOrder rideOrder = this.getById(orderId);
        Assert.notNull(rideOrder, "订单不存在");
        this.closeLock(rideOrder, CommonConstant.ONE, CommonConstant.ONE,false, customMoney, true, UserTypeEnum.AGENT.getCode(), userId, userName);
    }

    @Override
    public void sysCloseLock(SysCloseOrderForm sysCloseOrderForm) {
        EbRideOrder rideOrder = this.getById(sysCloseOrderForm.getOrderId());
        Assert.notNull(rideOrder, "订单不存在");
        this.closeLock(rideOrder, CommonConstant.ONE, CommonConstant.ONE,
            false, null,
            true, UserTypeEnum.SYS.getCode(),
            0, StrUtil.isEmpty(sysCloseOrderForm.getSysName()) ? "系统" : sysCloseOrderForm.getSysName());
    }

    /**
     * 结束关锁
     */
    @Override
    public void memberCloseLock(String orderNo, Integer memberId, MemberLocationDisptachForm memberLocationForm) {
        EbRideOrder rideOrder = this.getByNo(orderNo, memberId);
        Assert.notNull(rideOrder, "订单不存在");

        EbMemberInfo memberInfo = memberInfoService.getById(memberId);
        this.closeLock(rideOrder, memberLocationForm.getIsDispatch(),  memberLocationForm.getPayHelmetMoney(),true, null, false, UserTypeEnum.MEMBER.getCode(), memberId, memberInfo.getName());

        this.update(new LambdaUpdateWrapper<EbRideOrder>()
                .set(EbRideOrder::getMemberEndLat, memberLocationForm.getLat())
                .set(EbRideOrder::getMemberEndLng, memberLocationForm.getLng())
                .eq(EbRideOrder::getId, rideOrder.getId()));
    }

    /**
     * 关锁统一处理
     */
    private void closeLock(EbRideOrder rideOrder, Integer isDispatch, Integer payHelmetMoney, boolean sendCommand, BigDecimal customMoney, boolean superRole, Integer userType, Integer userId, String userName) {
        // 直接结束订单
        if (rideOrder.getStatus().equals(RideOrderStatusEnum.INIT.getCode())) {
            // 不能随便关闭车辆
            this.failInitOrder(rideOrder.getId());
            return;
        }

        EbDeviceBike deviceBike = deviceBikeService.getById(rideOrder.getBikeId());

        Assert.isTrue(StrUtil.isNotBlank(deviceBike.getControlNo()), "控制编码不存在");
        Assert.isTrue(!rideOrder.getStatus().equals(RideOrderStatusEnum.COMPLETE.getCode()), "当前订单已结束");
        Assert.isTrue(!rideOrder.getStatus().equals(RideOrderStatusEnum.CONFIRM.getCode()), "当前订单已进入确认状态");
        if (!superRole) deviceBikeService.checkCloseBike(deviceBike, rideOrder, isDispatch, payHelmetMoney, userId, userName);

        String redisKey = "CMD:BIKE:ORDER:LOCK:" + rideOrder.getOrderNo();
        Assert.isTrue(!redisService.hasKey(redisKey), "请勿频繁操作");
        redisService.set(redisKey, true, 3);

        // 订单费用结算
        this.orderSettleForClose(rideOrder, customMoney, userType);

        if (sendCommand) {
            // 等待中控反馈关锁
            try {
                rideCommandService.addCommand(rideOrder, DeviceCommandEnum.CLOSE_LOCK, userType, userId, userName);
            } catch (BadResponseException e) {
                // 中控离线，不影响用户还车，自动任务自己去继续关锁
                if (e.getCode() == 801) {
                    log.error("中控离线，支持关闭订单：{}", rideOrder.getOrderNo());
                    rideOrderService.orderBikeReturn(rideOrder.getId(), false, userType);
                    rideOrderService.confirmAutoPay(rideOrder.getId(), userType);
                } else {
                    throw e;
                }
            }
        } else {
            try {
                // 自行关锁，关锁失败也无所谓，结束订单
                SendBikeCommandForm commandForm = new SendBikeCommandForm()
                        .setAgentId(LocalMapUtil.getAgentInfo().getId())
                        .setBikeNo(deviceBike.getBikeNo())
                        .setCommand(DeviceCommandEnum.CLOSE_LOCK.getType())
                        .setUserId(userId)
                        .setUserName(userName)
                        .setUserType(userType)
                        .setIsSync(CommonConstant.ZERO);
                iotBikeClient.sendBikeCommand(commandForm);
            } catch (Exception e) {
                log.error("iotBikeClient.sendBikeCommand error", e);
            }

            rideOrderService.orderBikeReturn(rideOrder.getId(), false, userType);
            rideOrderService.confirmAutoPay(rideOrder.getId(), userType);

            // 如果有一条骑行指令正在执行，则结束
            rideCommandService.endCommand(rideCommandService.getCommand(rideOrder.getId(), DeviceCommandEnum.OPEN_LOCK, RideCommandStatusEnum.START, RideCommandTypeEnum.RIDE));

            // 如果有一条暂停指令正在执行，则结束
            rideCommandService.endCommand(rideCommandService.getCommand(rideOrder.getId(), DeviceCommandEnum.STOP_LOCK, RideCommandStatusEnum.START, RideCommandTypeEnum.RIDE));

        }
    }

    @Override
    public RidingVo riding(Integer memberId) {
        EbRideOrder rideOrder = this.getOne(new LambdaQueryWrapper<EbRideOrder>().eq(EbRideOrder::getMemberId, memberId)
                .in(EbRideOrder::getStatus, RideOrderStatusEnum.INIT.getCode(), RideOrderStatusEnum.RIDING.getCode(), RideOrderStatusEnum.PAUSE.getCode())
                .orderByDesc(EbRideOrder::getId)
                .last("limit 1"));
        Assert.notNull(rideOrder, "找不到骑行中的订单");
        // 初始化的订单，可能指令会不响应
        if (rideOrder.getStatus().equals(RideOrderStatusEnum.INIT.getCode())) {
            EbRideCommand initCommand = rideCommandService.getCommand(rideOrder.getId(), DeviceCommandEnum.OPEN_LOCK.getType(), RideCommandStatusEnum.INIT, RideCommandTypeEnum.RIDE);
            // initCommand 有可能还没有生成
            // 订单开锁指令大于3秒 小于15秒仍未响应（防止长时间status=0，重新被激活）
            if (initCommand != null && DateUtil.betweenMs(initCommand.getCreateTime(), new Date()) > 3000 && DateUtil.betweenMs(initCommand.getCreateTime(), new Date()) < 15000) {
                EbDeviceBike deviceBike = deviceBikeService.getById(rideOrder.getBikeId());
                if (CommonConstant.ONE.equals(deviceBike.getLockStatus())) {
                    // 模拟开锁
                    rideCommandService.orderOpenCommand(deviceBike, rideOrder, initCommand, "未响应补充开启订单");
                    // 重新拉取
                    rideOrder = this.getById(rideOrder);
                }
            }
        }
        RideOrderCountVo rideOrderCountVo = this.getOrderCount(rideOrder, rideOrder.getCloseTime() == null ? new Date() : rideOrder.getCloseTime(), true, false);

        rideOrderCountVo.setOrderNo(rideOrder.getOrderNo());
        rideOrderCountVo.setStatus(rideOrder.getStatus());
        rideOrderCountVo.setOpenTime(rideOrder.getOpenTime());
        rideOrderCountVo.setStopTime(rideOrder.getStopTime());
        rideOrderCountVo.setCloseTime(rideOrder.getCloseTime());

        RidingVo ridingVo = new RidingVo();
        BeanUtil.copyProperties(rideOrder, ridingVo);
        ridingVo.setOrderCount(rideOrderCountVo);
        ridingVo.setDeviceBike(deviceBikeService.getBike(rideOrder.getBikeNo()));
        return ridingVo;
    }

    @Override
    public void updateOrderRiding(Integer orderId, RideOrderCountVo rideOrderCountVo) {
        BigDecimal timeMoneyReal = rideOrderCountVo.getBeforeTimeMoney().add(rideOrderCountVo.getOverRideTimeMoney());
        BigDecimal distanceMoneyReal = rideOrderCountVo.getBeforeDistanceMoney().add(rideOrderCountVo.getOverDistanceMoney());
        rideOrderService.update(new LambdaUpdateWrapper<EbRideOrder>()
                .set(EbRideOrder::getAllTime, rideOrderCountVo.getAllTime())
                .set(EbRideOrder::getAllDistance, rideOrderCountVo.getAllDistance())
                .set(EbRideOrder::getFreeTime, rideOrderCountVo.getFreeTime())
                .set(EbRideOrder::getNewFreeTime, rideOrderCountVo.getNewFreeTime())
                .set(EbRideOrder::getCardRecordId, rideOrderCountVo.getCardRecordId())
                .set(EbRideOrder::getCardFreeTime, rideOrderCountVo.getCardFreeTime())
                .set(EbRideOrder::getCardFreeMoney, rideOrderCountVo.getCardFreeMoney())
                .set(EbRideOrder::getRideTime, rideOrderCountVo.getRideTime())
                .set(EbRideOrder::getBeforeTime, rideOrderCountVo.getBeforeTime())
                .set(EbRideOrder::getBeforeTimeMoney, rideOrderCountVo.getBeforeTimeMoney())
                .set(EbRideOrder::getBeforeDistance, rideOrderCountVo.getBeforeDistance())
                .set(EbRideOrder::getBeforeDistanceMoney, rideOrderCountVo.getBeforeDistanceMoney())
                .set(EbRideOrder::getOverTime, rideOrderCountVo.getOverTime())
                .set(EbRideOrder::getOverRideTimeMoney, rideOrderCountVo.getOverRideTimeMoney())
                .set(EbRideOrder::getRideDistance, rideOrderCountVo.getRideDistance())
                .set(EbRideOrder::getOverDistance, rideOrderCountVo.getOverDistance())
                .set(EbRideOrder::getOverDistanceMoney, rideOrderCountVo.getOverDistanceMoney())
                .set(EbRideOrder::getTimeMoneyReal, timeMoneyReal)
                .set(EbRideOrder::getDistanceMoneyReal, distanceMoneyReal)
                .set(EbRideOrder::getBeforeMoney, timeMoneyReal.add(distanceMoneyReal))
                .set(EbRideOrder::getCouponId, rideOrderCountVo.getCouponId())
                .set(EbRideOrder::getCouponMoney, rideOrderCountVo.getCouponMoney())
                .set(EbRideOrder::getMoney, rideOrderCountVo.getMoney())
                .set(EbRideOrder::getOrderMoney, rideOrderCountVo.getOrderMoney())
                .set(EbRideOrder::getCappingDistance, rideOrderCountVo.getCappingDistance())
                .set(EbRideOrder::getCappingDistanceMoney, rideOrderCountVo.getCappingDistanceMoney())
                .set(EbRideOrder::getCappingTime, rideOrderCountVo.getCappingTime())
                .set(EbRideOrder::getCappingTimeMoney, rideOrderCountVo.getCappingTimeMoney())
                .set(EbRideOrder::getModifyTime, new Date())
                .eq(EbRideOrder::getId, orderId));
    }

    @Override
    public void memberCheckStop(String orderNo, Integer aiPhotosPass, Integer memberId) {
        EbRideOrder ebRideOrder = this.getByNo(orderNo, memberId);
        Assert.notNull(ebRideOrder, "订单不存在");
        Assert.isTrue(RideOrderStatusEnum.RIDING.getCode().equals(ebRideOrder.getStatus()) || RideOrderStatusEnum.PAUSE.getCode().equals(ebRideOrder.getStatus()), "订单状态不支持当前操作");

        // 区域参数配置信息
        BikeAreaParam bikeAreaParam = agentParamCacheService.getParam(ebRideOrder.getAgentId(), ebRideOrder.getAreaId());

        // 车辆信息
        EbDeviceBike deviceBike = deviceBikeService.getByNo(ebRideOrder.getBikeNo());
        Assert.notNull(deviceBike, "车辆信息不存在");
        if(deviceBike.getStationId() != null) {
            // 站点配置规范停车
            EbOperationStation operationStation = operationStationService.getById(deviceBike.getStationId());
            if(operationStation != null){
                if (operationStation.getCameraStopEnabled() != null && operationStation.getCameraStopEnabled().equals(CommonConstant.ONE)) {
                    bikeAreaParam.setUserCameraAIStopBike(true);
                    if (operationStation.getCameraStopAngle() != null && operationStation.getCameraStopAngle() > 0) {
                        bikeAreaParam.setUserCameraStopAngle(operationStation.getCameraStopAngle());
                    }
                    if (operationStation.getCameraStopDistance() != null && operationStation.getCameraStopDistance() > 0) {
                        bikeAreaParam.setUserCameraStopAngle(operationStation.getCameraStopDistance());
                    }
                } else if (operationStation.getCameraStopEnabled() != null && operationStation.getCameraStopEnabled().equals(CommonConstant.ZERO)) {
                    bikeAreaParam.setUserCameraAIStopBike(false);
                }
                if (operationStation.getSpikeStopEnabled() != null && operationStation.getSpikeStopEnabled().equals(CommonConstant.ONE)) {
                    bikeAreaParam.setUserSpikeStopBike(true);
                    if (operationStation.getSpikeSignalStrength() != null && operationStation.getSpikeSignalStrength() > 0) {
                        bikeAreaParam.setUserSpikeSignalStrength(operationStation.getSpikeSignalStrength());
                    }
                } else if (operationStation.getSpikeStopEnabled() != null && operationStation.getSpikeStopEnabled().equals(CommonConstant.ZERO)) {
                    bikeAreaParam.setUserSpikeStopBike(false);
                }
            }
        }
        // 区域配置规范停车
        this.areaConfigCheck(deviceBike.getAgentId(), bikeAreaParam, deviceBike.getBikeNo(), aiPhotosPass);
    }

    private void areaConfigCheck(Integer agentId, BikeAreaParam bikeAreaParam, String bikeNo, Integer aiPhotosPass){
        if(bikeAreaParam.getUserCameraAIStopBike() || bikeAreaParam.getUserSpikeStopBike()) {
            AjaxResult res = null;
            if (bikeAreaParam.getUserCameraAIStopBike()) {
                CloseLockRequest closeLockRequest = new CloseLockRequest();
                closeLockRequest.setIsCameraStop(CommonConstant.ONE);
                closeLockRequest.setCameraStopAngle(bikeAreaParam.getUserCameraStopAngle());
                closeLockRequest.setCameraStopColour(bikeAreaParam.getUserCameraStopColor());
                closeLockRequest.setCameraStopDistance(bikeAreaParam.getUserCameraStopDistance());
                res = iotBikeClient.cameraCloseQuery(agentId, bikeNo, closeLockRequest);
                log.info("AI停车结果:{}", JSONObject.toJSONString(res));
            }

            if (!bikeAreaParam.getUserSpikeStopBike() && res != null && !res.isSuccess()) {
                deviceBikeService.noInStopAreaSendVoice(agentId, bikeNo, "摄像头停车失败提醒");
                throw new BadResponseException(508, res.getMessage());
            }

            if ((res == null || !res.isSuccess()) && bikeAreaParam.getUserSpikeStopBike()) {
                res = iotBikeClient.beaconsQuery(agentId, bikeNo, bikeAreaParam.getUserSpikeSignalStrength());
                log.info("道钉停车结果:{}", JSONObject.toJSONString(res));
            }
            if (res != null && !res.isSuccess()) {
                deviceBikeService.noInStopAreaSendVoice(agentId, bikeNo, "道钉停车失败提醒");
                throw new BadResponseException(509, res.getMessage());
            }

            if ((bikeAreaParam.getUserCameraAIStopBike() || bikeAreaParam.getUserSpikeStopBike()) && res == null) {
                deviceBikeService.noInStopAreaSendVoice(agentId, bikeNo, "规范停车失败提醒");
                throw new BadResponseException(510, "用户停车规范判断异常");
            }
        }
        // 如果开通了AI拍照规范停车 抛出异常代码引导用户AI拍照停车
        if(aiPhotosPass == null || aiPhotosPass.equals(CommonConstant.ZERO)) {
            if(bikeAreaParam.getUserRideAIPhotosStopBike()) {
                throw new BadResponseException(524, "区域开启AI拍照停车");
            }
        }
    }

    /**
     * 骑行中订单金额修改
     * @param agentUser
     * @param ebRideOrder
     * @param form
     */
    @Override
    public void orderUpdateMoney(AgentUser agentUser, EbRideOrder ebRideOrder, RideSysUpdateMoneyForm form) {
        if(!ebRideOrder.getStatus().equals(RideOrderStatusEnum.RIDING.getCode()) &&
                !ebRideOrder.getStatus().equals(RideOrderStatusEnum.PAUSE.getCode())) {
            throw new BadResponseException("此功能只支持骑行中订单金额修改");
        }
        // 直接结束订单
        if(form.getIsClose() != null && form.getIsClose().equals(CommonConstant.ZERO)){
            // 结束订单
            this.closeLock(ebRideOrder, CommonConstant.ONE, CommonConstant.ONE,false, null, true, UserTypeEnum.ADMIN.getCode(), agentUser.getId(), agentUser.getName());
            return;
        }

        if(ebRideOrder.getOrderMoney() == null) ebRideOrder.setOrderMoney(ebRideOrder.getMoney());
        if(ebRideOrder.getDispatchMoney() == null) ebRideOrder.setDispatchMoney(BigDecimal.ZERO);
        if(ebRideOrder.getHelmetPay() == null) ebRideOrder.setHelmetPay(BigDecimal.ZERO);

        BigDecimal oriMoney = BigDecimal.ZERO;
        BigDecimal payMoney = BigDecimal.ZERO;
        LambdaUpdateWrapper<EbRideOrder> updateWrapper = new LambdaUpdateWrapper<>();
        for(int i = 0; i < 3; i++) {
            if (Integer.valueOf(i).equals(CommonConstant.ZERO) && form.getOrderMoney() != null && (ebRideOrder.getOrderMoney().compareTo(form.getOrderMoney()) != 0 || form.getOrderMoney().compareTo(BigDecimal.ZERO) == 0)) {
                oriMoney = ebRideOrder.getOrderMoney();
                updateWrapper.set(EbRideOrder::getOrderMoney, form.getOrderMoney());
                payMoney = payMoney.add(form.getOrderMoney());
                // 生成修改记录
                rideModifyService.createRecord(agentUser, ebRideOrder, CommonConstant.TWO, oriMoney, form.getOrderMoney(), form.getRemark());
            } else if(Integer.valueOf(i).equals(CommonConstant.ZERO) && form.getOrderMoney() != null && ebRideOrder.getOrderMoney().compareTo(form.getOrderMoney()) == 0){
                payMoney = payMoney.add(ebRideOrder.getOrderMoney());
            }

            if (Integer.valueOf(i).equals(CommonConstant.ONE) && form.getDispatchMoney() != null && (ebRideOrder.getDispatchMoney().compareTo(form.getDispatchMoney()) != 0 || form.getDispatchMoney().compareTo(BigDecimal.ZERO) == 0)) {
                oriMoney = ebRideOrder.getDispatchMoney();
                updateWrapper.set(EbRideOrder::getDispatchMoney, form.getDispatchMoney());
                payMoney = payMoney.add(form.getDispatchMoney());
                // 生成修改记录
                rideModifyService.createRecord(agentUser, ebRideOrder, CommonConstant.THREE, oriMoney, form.getDispatchMoney(), form.getRemark());
            } else if(Integer.valueOf(i).equals(CommonConstant.ONE) && form.getDispatchMoney() != null && ebRideOrder.getDispatchMoney().compareTo(form.getDispatchMoney()) == 0){
                payMoney = payMoney.add(ebRideOrder.getDispatchMoney());
            }

            if (Integer.valueOf(i).equals(CommonConstant.TWO) && form.getHelmetMoney() != null && (ebRideOrder.getHelmetPay().compareTo(form.getHelmetMoney()) != 0 || form.getHelmetMoney().compareTo(BigDecimal.ZERO) == 0)) {
                oriMoney = ebRideOrder.getHelmetPay();
                updateWrapper.set(EbRideOrder::getHelmetPay, form.getHelmetMoney());
                payMoney = payMoney.add(form.getHelmetMoney());
                // 生成修改记录
                rideModifyService.createRecord(agentUser, ebRideOrder, CommonConstant.FOUR, oriMoney, form.getHelmetMoney(), form.getRemark());
            }else if(Integer.valueOf(i).equals(CommonConstant.TWO) && form.getHelmetMoney() != null && ebRideOrder.getHelmetPay().compareTo(form.getHelmetMoney()) == 0){
                payMoney = payMoney.add(ebRideOrder.getHelmetPay());
            }
        }
        updateWrapper.set(EbRideOrder::getCloseType, RideOrderCloseTypeEnum.CUSTOMER.getCode());
        updateWrapper.eq(EbRideOrder::getId, ebRideOrder.getId());


        // 生成总价修改记录
        rideModifyService.createRecord(agentUser, ebRideOrder, CommonConstant.ONE, ebRideOrder.getMoney(), payMoney, form.getRemark());

        // 结束订单
        this.closeLock(ebRideOrder, CommonConstant.ONE, CommonConstant.ONE,false, payMoney, true, UserTypeEnum.ADMIN.getCode(), agentUser.getId(), agentUser.getName());

        // 修改订单金额 结算类型
        this.update(updateWrapper);
    }

    @Override
    public void bikeCloseOrder(Integer bikeId) {
        EbRideOrder rideOrder = this.getByBike(bikeId);
        EbMemberInfo memberInfo = memberInfoService.getById(rideOrder.getMemberId());
        this.closeLock(rideOrder, CommonConstant.ONE,  CommonConstant.ONE,true, null, false, UserTypeEnum.MEMBER.getCode(), memberInfo.getId(), memberInfo.getName());

        EbDeviceBike deviceBike = deviceBikeService.getById(rideOrder.getBikeId());
        this.update(new LambdaUpdateWrapper<EbRideOrder>()
                .set(EbRideOrder::getMemberEndLat, deviceBike.getLat())
                .set(EbRideOrder::getMemberEndLng, deviceBike.getLng())
                .eq(EbRideOrder::getId, rideOrder.getId()));
    }

    @Override
    public List<RideOrderUseCardFeeVo> rideUseCard(String orderNo, Integer memberId) {
        EbRideOrder rideOrder = this.getByNo(orderNo, memberId);
       if(rideOrder == null) return new ArrayList<>();

        Assert.isTrue(rideOrder.getStatus().equals(RideOrderStatusEnum.CONFIRM.getCode()), "订单未结束或已完成");
        if (rideOrder.getDispatchMoney().compareTo(BigDecimal.ZERO) > 0) {
            throw new BadResponseException("罚款订单不支持购买骑行卡");
        }
        EbPriceRule priceRule = priceRuleService.getRule(rideOrder.getAreaId());
        Assert.notNull(priceRule, "未获取到价格方案");

        List<RideOrderUseCardFeeVo> cardFeeVos = new ArrayList<>();
        List<EbCardInfo> cardInfos = cardInfoService.getInfoList(rideOrder.getAreaId());
        for(EbCardInfo cardInfo : cardInfos) {
            RideOrderUseCardFeeVo cardFeeVo = new RideOrderUseCardFeeVo();
            cardFeeVo.setCardId(cardInfo.getId());
            cardFeeVo.setCardName(cardInfo.getTitle());
            cardFeeVo.setPrice(cardInfo.getPrice());
            cardFeeVo.setOtherPrice(cardInfo.getOtherPrice());
            cardFeeVo.setCouponType(cardInfo.getCouponType());

            // 时间减免
            if (cardInfo.getCouponType().equals(CardInfoCouponTypeEnum.TIME.getCode())) {
                Assert.isTrue(cardInfo.getCouponTime() != null, "骑行卡不可用");
                // 使用骑行卡减免之后的计费骑行时长
                Integer orderFreeAfterTime = rideOrder.getRideTime() - cardInfo.getCouponTime();
                if (orderFreeAfterTime > 0) {
                    // 减免之后时长费用
                    BigDecimal freeAfterTimeMoney = BigDecimal.ZERO;
                    if(priceRule.getIsStep() == null || priceRule.getIsStep().equals(CommonConstant.ZERO)) {
                        freeAfterTimeMoney = OrderPriceUtil.getBasicRideMoney(orderFreeAfterTime, priceRule);
                    }else {
                        List<EbPriceStep>  priceSteps = priceStepService.getAreaPriceStep(priceRule.getAreaId());
                        freeAfterTimeMoney = OrderPriceUtil.getBasicRideMoney(orderFreeAfterTime, priceRule, priceSteps);
                    }
                    cardFeeVo.setOrderFreeTime(rideOrder.getOrderMoney().subtract(freeAfterTimeMoney));
                } else {
                    cardFeeVo.setOrderFreeTime(rideOrder.getOrderMoney());
                }

                // 减免金额
            } else if (cardInfo.getCouponType().equals(CardInfoCouponTypeEnum.MONEY.getCode())) {
                Assert.notNull(cardInfo.getCouponMoney(), "骑行卡不可用");
                cardFeeVo.setOrderFreeMoney(cardInfo.getCouponMoney());
            } else {
                throw new BadResponseException("选择的骑行卡不支持使用");
            }

            cardFeeVo.setCardFreeMoney(cardFeeVo.getOrderFreeMoney().add(cardFeeVo.getOrderFreeTime()));
            cardFeeVo.setOrderMoney(rideOrder.getOrderMoney().subtract(cardFeeVo.getOrderFreeMoney()).subtract(cardFeeVo.getOrderFreeTime()));
            cardFeeVo.setMoney(rideOrder.getMoney().subtract(cardFeeVo.getOrderFreeMoney()).subtract(cardFeeVo.getOrderFreeTime()));
            if(cardFeeVo.getOrderMoney().compareTo(BigDecimal.ZERO) < 0) {
                cardFeeVo.setOrderMoney(BigDecimal.ZERO);
            }
            if(cardFeeVo.getMoney().compareTo(BigDecimal.ZERO) < 0) {
                cardFeeVo.setMoney(BigDecimal.ZERO);
            }
            cardFeeVos.add(cardFeeVo);
        }
        return cardFeeVos;
    }

    @Override
    public void orderConsumeMemberCard(Integer rideOrderId, Integer memberCardId, Integer userType) {
        EbRideOrder rideOrder = this.getById(rideOrderId);
        if(rideOrder == null) return;
        if(!rideOrder.getStatus().equals(RideOrderStatusEnum.CONFIRM.getCode())) return;

        MemberCouponVo memberCouponVo = null;
        if(rideOrder.getCouponId() != null) {
            memberCouponVo = memberCouponService.getByCouponId(rideOrder.getCouponId());
        }

        MemberCardVo memberCard = memberCardService.detail(memberCardId);

        BikeAreaParam bikeParam = agentParamCacheService.getParam(rideOrder.getAgentId(), rideOrder.getAreaId());
        boolean allowCoupon = rideOrder.getDispatchMoney().compareTo(new BigDecimal(0)) > 0 ? bikeParam.getUserDispatchAllowDiscount() : true;
        if(!allowCoupon) return;

        RideOrderCountVo rideOrderCountVo = this.getOrderCount(rideOrder, rideOrder.getCloseTime(), allowCoupon, memberCard, memberCouponVo, true);
        if(rideOrderCountVo.getCardRecordId() == null) return;
        // 订单金额
        rideOrderCountVo.setMoney(rideOrderCountVo.getMoney().add(rideOrder.getDispatchMoney()).add(rideOrder.getHelmetPay()));
        this.updateOrderRiding(rideOrderId, rideOrderCountVo);

        if (rideOrderCountVo.getCardRecordId() != null) {
            memberCardService.costTimes(rideOrderCountVo.getCardRecordId(), rideOrderCountVo.getCardFreeMoney());
        }
        if(rideOrderCountVo.getCouponId() != null) {
            memberCouponService.useCoupon(rideOrderCountVo.getCouponId());
        }

        // 自动付款
        if(rideOrderCountVo.getMoney().compareTo(BigDecimal.ZERO) <= 0) {
            this.confirmAutoPay(rideOrder.getId(), userType);
        }
    }

    @Override
    public GetCloseResultVo getCloseResult(String orderNo, Integer memberId, Integer userType) {
        RideOrderVo rideOrderVo = rideOrderMapper.selectOrder(orderNo, memberId);
        Assert.notNull(rideOrderVo, "订单不存在：" + orderNo);
        // 先不处理暂停中车辆，只处理骑行中车辆
        if (rideOrderVo.getStatus().equals(RideOrderStatusEnum.RIDING.getCode())) {
            EbRideCommand initCommand = rideCommandService.getCommand(rideOrderVo.getId(), DeviceCommandEnum.CLOSE_LOCK.getType(), RideCommandStatusEnum.INIT, RideCommandTypeEnum.RIDE);
            // initCommand 有可能还没有生成
            // 订单开锁指令大于3000秒仍未响应
            if (initCommand != null && DateUtil.betweenMs(initCommand.getCreateTime(), new Date()) > 3000) {
                EbDeviceBike deviceBike = deviceBikeService.getById(rideOrderVo.getBikeId());
                // 如果车辆已关锁
                if (CommonConstant.ZERO.equals(deviceBike.getLockStatus())) {
                    // 模拟关锁
                    rideCommandService.orderCloseCommand(deviceBike, rideOrderVo, initCommand, "未响应补充关闭订单", userType);
                    // 重新拉取
                    rideOrderVo = rideOrderMapper.selectOrder(orderNo, memberId);
                }
            }
        }
        GetCloseResultVo vo = new GetCloseResultVo();
        BeanUtils.copyProperties(rideOrderVo, vo);
        return vo;
    }

    @Override
    public EbRideOrder getNoUseCardWaitPayOrder(Integer memberId) {
        return this.getOne(new LambdaQueryWrapper<EbRideOrder>()
                .eq(EbRideOrder::getStatus, RideOrderStatusEnum.CONFIRM.getCode())
                .isNull(EbRideOrder::getCardRecordId)
                .eq(EbRideOrder::getMemberId, memberId)
                .orderByDesc(EbRideOrder::getId)
                .last("limit 0,1"));
    }

    @Override
    public void memberOrderBell(String orderNo, Integer memberId) {
        EbRideOrder rideOrder = getByNo(orderNo, memberId);
        Assert.notNull(rideOrder, "订单不存在");
        Assert.isTrue(rideOrder.getStatus().equals(RideOrderStatusEnum.PAUSE.getCode())
                || rideOrder.getStatus().equals(RideOrderStatusEnum.RIDING.getCode()), "订单不支持寻车响铃");
        try {
            EbMemberInfo memberInfo = memberInfoService.getById(memberId);
            SendBikeCommandForm commandForm = new SendBikeCommandForm()
                    .setAgentId(LocalMapUtil.getAgentInfo().getId())
                    .setBikeNo(rideOrder.getBikeNo())
                    .setCommand(DeviceCommandEnum.BELL.getType())
                    .setUserId(memberInfo.getId())
                    .setUserName(memberInfo.getName())
                    .setUserType(UserTypeEnum.MEMBER.getCode());
            iotBikeClient.sendBikeCommand(commandForm);
        }catch (Exception ex) {
            log.info("订单响铃发送失败:{}", ex.getMessage());
        }
    }

    @Override
    public void memberAiPhotosStop(MultipartFile file, Integer isDispatch, String orderNo, Integer memberId) {
        EbRideOrder rideOrder = this.getByNo(orderNo, memberId);
        Assert.notNull(rideOrder, "订单不存在");
        Assert.isTrue(RideOrderStatusEnum.RIDING.getCode().equals(rideOrder.getStatus())
                || RideOrderStatusEnum.PAUSE.getCode().equals(rideOrder.getStatus()), "订单已结束");
        EbDeviceBike deviceBike = deviceBikeService.getById(rideOrder.getBikeId());
        Assert.notNull(deviceBike, "车辆不存在");
        Assert.isTrue(StrUtil.isNotBlank(deviceBike.getLicensePlate()), "未识别到车牌");

        EbPhotosStop ebPhotosStop = new EbPhotosStop();
        ebPhotosStop.setAreaId(rideOrder.getAreaId());
        ebPhotosStop.setOrderId(rideOrder.getId());
        ebPhotosStop.setOrderNo(rideOrder.getOrderNo());
        ebPhotosStop.setMemberId(memberId);
        ebPhotosStop.setBikeId(deviceBike.getId());
        ebPhotosStop.setBikeNo(deviceBike.getBikeNo());
        ebPhotosStop.setLicensePlate(deviceBike.getLicensePlate());

        BikeAreaParam bikeAreaParam = agentParamCacheService.getParam(rideOrder.getAgentId(), rideOrder.getAreaId());
        Assert.notNull(bikeAreaParam, "区域参数配置信息异常");
        // 订单关锁记录
        EbRideClose rideClose = rideCloseService.getByOrderCode(orderNo);
        EbPriceRule priceRule = priceRuleService.getRule(rideOrder.getAreaId());
        if(rideClose != null) {
            // 停车规范检查项
            JSONObject closeCheckItem = StrUtil.isBlank(rideClose.getCloseCheckItem()) ? new JSONObject() : JSONObject.parseObject(rideClose.getCloseCheckItem());
            closeCheckItem.put("userRideAIPhotosStopBike", bikeAreaParam.getUserRideAIPhotosStopBike());
            closeCheckItem.put("userAIPhotosStopBikeScheme", bikeAreaParam.getUserAIPhotosStopBikeScheme());
            closeCheckItem.put("userAIPhotosStopApiParams", bikeAreaParam.getUserAIPhotosStopApiParams());
            rideClose.setCloseCheckItem(closeCheckItem.toJSONString());
        }

        // 获取文件file对象
        File photosFile = null;
        // 当同意调度费时不在上传图片 因为收到同意调度费说明已走过验证
        if(isDispatch == null || isDispatch.equals(CommonConstant.ZERO)) {
            try {
                photosFile = new File("ai_photos_bike".concat(file.getOriginalFilename()));
                photosFile.createNewFile();
                Files.copy(file.getInputStream(), photosFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            } catch (Exception ex) {
                log.error("获取文件信息异常:{}", ex.getMessage());
                // 删除本地缓存图片文件
                if (photosFile != null && photosFile.exists()) {
                    photosFile.delete();
                }
                throw new BadResponseException("未获取到图片");
            }
            try {
                String extName = FileUtil.getSuffix(file.getOriginalFilename());
                String fileName = RandomUtil.randomString(32) + (StrUtil.isNotBlank(extName) ? ("." + extName) : "");
                String filePath = "files/user/photos/" + DateUtil.format(new Date(), "yyyyMM") + "/" + fileName;
                String url = ossService.putObject(filePath, file.getInputStream());
                ebPhotosStop.setImageUrl(url);
            } catch (Exception ex) {
                log.error("AI拍照停车上传sls异常:{}", ex.getMessage());
            }
        }
        try {
            // 当同意调度费时不在上传图片 因为收到同意调度费说明已走过验证
            if(isDispatch == null || isDispatch.equals(CommonConstant.ZERO)) {
                // 华惠 AI图片检查
                if (bikeAreaParam.getUserAIPhotosStopBikeScheme() == null
                        || bikeAreaParam.getUserAIPhotosStopBikeScheme().equals(CommonConstant.ONE)) {
                    ebPhotosStop.setCheckProgram(CommonConstant.ONE);

                    photosStopService.huaHuiPhotosCheck(ebPhotosStop, bikeAreaParam.getUserAIPhotosStopApiParams(), photosFile, deviceBike.getLicensePlate());

                } else {
                    throw new BadResponseException("不支持的AI图片检查方案");
                }
            } else {
                throw new BadResponseException("AI拍照还车未通过, 同意支付调度费还车");
            }
        }catch (Exception ex) {
            // 删除本地缓存图片文件
            if(photosFile != null && photosFile.exists()) {
                photosFile.delete();
            }
            ebPhotosStop.setEndTime(DateUtil.date());
            photosStopService.save(ebPhotosStop);

            if(rideClose != null) {
                rideClose.setAreaCheckResult(CommonConstant.ONE);
                rideClose.setPayDispatchMoney(isDispatch);
                rideClose.setDispatchType(CommonConstant.ONE);
                rideClose.setCloseCheckResult(CommonConstant.ZERO);
                // 尚未同意调度费 发送还车失败语音 防止与锁车指令冲突
                if (isDispatch == null || CommonConstant.ZERO.equals(isDispatch)) {
                    JSONObject closeCheckRule = new JSONObject();
                    closeCheckRule.put("code", 500);
                    closeCheckRule.put("message", ex.getMessage());
                    rideClose.setCloseCheckRule(closeCheckRule.toJSONString());
                    this.noInStopAreaSendVoice(deviceBike.getAgentId(), deviceBike.getBikeNo(), "AI拍照还车失败提醒");
                }

                BigDecimal stationDispatchFee = BigDecimal.ZERO;
                if (priceRule.getIsOpenDispatch().equals(CommonConstant.ONE)) {
                    if (priceRule.getStationDispatchFee().compareTo(new BigDecimal(0)) > 0) {
                        if (isDispatch == null || isDispatch.equals(CommonConstant.ZERO)) {
                            stationDispatchFee = priceRule.getStationDispatchFee();
                            // 获取当前车辆最新订单
                            EbRideOrder ebRideOrder = rideOrderService.getOne(new LambdaQueryWrapper<EbRideOrder>()
                                    .eq(EbRideOrder::getBikeId, deviceBike.getId())
                                    .orderByDesc(EbRideOrder::getId)
                                    .last("limit 0,1"));
                            if (ebRideOrder != null) {
                                Long diffMinute = DateUtil.between(ebRideOrder.getOpenTime(), DateUtil.date(), DateUnit.SECOND);
                                if ((diffMinute <= priceRule.getFreeMinuteRiding() * 60) && priceRule.getIsRidingDispatch().equals(CommonConstant.ZERO)) {
                                    stationDispatchFee = BigDecimal.ZERO;
                                }
                            }
                            // 保存信息
                            rideCloseService.updateById(rideClose);
                            JSONObject data = new JSONObject();
                            data.put("fee", stationDispatchFee);
                            throw new BadResponseException(522, "停车失败:" + ex.getMessage() + "，停车需支付" + stationDispatchFee + "元调度费", data);
                        }
                        stationDispatchFee = priceRule.getStationDispatchFee();
                    }
                } else {
                    // 保存信息
                    rideCloseService.updateById(rideClose);
                    throw new BadResponseException(502, "停车失败:" + ex.getMessage() +", 请按照提示规范停车");
                }
                rideClose.setDispatchMoney(stationDispatchFee);
            } else {
                throw new BadResponseException(ex.getMessage());
            }
        }

        // 删除本地缓存图片文件
        if(photosFile != null && photosFile.exists()) {
            photosFile.delete();
        }
        if(isDispatch == null || isDispatch.equals(CommonConstant.ZERO)) {
            if(ebPhotosStop.getId() == null || ebPhotosStop.getId() <= 0) {
                ebPhotosStop.setCheckStatus(PhotosStopCheckResultEnum.PASS.getCode());
                ebPhotosStop.setEndTime(DateUtil.date());
                photosStopService.save(ebPhotosStop);
            }
           if(rideClose != null) {
               rideClose.setAreaCheckResult(CommonConstant.TWO);
               rideClose.setPayDispatchMoney(isDispatch);
               rideClose.setDispatchType(CommonConstant.ONE);
               rideClose.setCloseCheckResult(CommonConstant.ONE);
           }
        }
        if(rideClose != null) {
            // 调度费减免
            rideCloseService.handleDispatchReduceMoney(true, rideClose, rideOrder, priceRule);
            // 保存信息
            rideCloseService.updateById(rideClose);
        }
    }

    @Override
    public RideOrderStopTimesVo orderStopTimes(String orderNo, Integer memberId) {
        EbRideOrder rideOrder = this.getByNo(orderNo, memberId);
        Assert.notNull(rideOrder, "订单不存在");
        RideOrderStopTimesVo vo = new RideOrderStopTimesVo();
        BikeAreaParam bikeAreaParam = agentParamCacheService.getParam(rideOrder.getAgentId(), rideOrder.getAreaId());
        if (bikeAreaParam != null && bikeAreaParam.getUserRideStopBikeMaxTimesEnabled()) {
            if (bikeAreaParam.getUserRideStopBikeMaxTimes() <= 0) {
                vo.setRemainStopLockTimes(CommonConstant.ZERO);
            } else {
                Integer orderStopLockTimes = rideCommandService.getCommandCount(rideOrder.getId(), DeviceCommandEnum.STOP_LOCK);
                vo.setRemainStopLockTimes(bikeAreaParam.getUserRideStopBikeMaxTimes() - orderStopLockTimes);
            }
        }
        return vo;
    }

    /**
     * 骑行卡今日骑行次数（按订单结束时间统计骑行卡当天消耗次数）
     */
    private long getTodayCardUserTimes(MemberCardVo memberCard) {
        Date now = new Date();
        return this.count(new LambdaQueryWrapper<EbRideOrder>()
                .eq(EbRideOrder::getAreaId, memberCard.getAreaId())
                .eq(EbRideOrder::getMemberId, memberCard.getMemberId())
                .eq(EbRideOrder::getCardRecordId, memberCard.getId())
                .eq(EbRideOrder::getStatus, RideOrderStatusEnum.COMPLETE.getCode())
                .ge(EbRideOrder::getCloseTime, DateUtil.beginOfDay(now))
                .le(EbRideOrder::getCloseTime, DateUtil.endOfDay(now)));
    }

    /**
     * 获取订单计费汇总信息
     */
    @Override
    public RideOrderCountVo getOrderCount(EbRideOrder rideOrder, Date closeTime, boolean allowCoupon, Boolean isClose) {
        return this.getOrderCount(rideOrder, closeTime, allowCoupon, null, null, isClose);
    }

    @Override
    public RideOrderCountVo getOrderCount(EbRideOrder rideOrder, Date closeTime, boolean allowCoupon, MemberCardVo appointMemberCard, MemberCouponVo appointMemberCoupon, Boolean isClose) {
        EbPriceRule priceRule = priceRuleService.getRule(rideOrder.getAreaId());

        RideOrderCountVo rideOrderCountVo = new RideOrderCountVo();
        if (rideOrder.getOpenTime() != null) {
            rideOrderCountVo.setAllTime(new Double(NumberUtil.div(DateUtil.betweenMs(rideOrder.getOpenTime(), closeTime), 60 * 1000, 0, RoundingMode.UP)).intValue());
            // 废弃从device_path表里获取距离逻辑
            // rideOrderCountVo.setAllDistance(devicePathService.getDistance(rideOrder.getBikeId(), rideOrder.getOpenTime(), closeTime, isClose));

            // 从骑行距离表 获取骑行距离
            rideOrderCountVo.setAllDistance(rideDistanceService.getDistance(rideOrder.getId(), rideOrder.getBikeId(), rideOrder.getStartLng(), rideOrder.getStartLat()));
        }

        // 免费骑行时间内，不计算金额 如果限制了免费骑行次数 没超过免费次数即可免费骑行
        Integer isFreeRide = CommonConstant.ONE;
        if(priceRule.getDayFreeTimes() > 0){
            List<EbRideOrder> freeRideOrders = baseMapper.getTodayFreeOrder(rideOrder.getMemberId());
            Integer rideFreeTimes = CommonConstant.ZERO;
            if(ArrayUtil.isAllNotEmpty(freeRideOrders)){
                List<Integer> orderIds = freeRideOrders.stream().map(item-> { return item.getId(); }).collect(Collectors.toList());
                if(orderIds.contains(rideOrder.getId())){
                    rideFreeTimes = orderIds.size();
                }else {
                    rideFreeTimes = orderIds.size() + 1;
                }
            }else{
                rideFreeTimes = CommonConstant.ONE;
            }
            if(rideFreeTimes > priceRule.getDayFreeTimes()){
                isFreeRide = CommonConstant.ZERO;
            }
        }
        if (priceRule.getFreeMinuteRiding() > 0 && rideOrderCountVo.getAllTime() <= priceRule.getFreeMinuteRiding() && isFreeRide.equals(CommonConstant.ONE)) {
            rideOrderCountVo.setFreeTime(priceRule.getFreeMinuteRiding());
            // 如果超过，则不记录免费骑行时长，其他地方将以freeTime判断是否是免费骑行
            return rideOrderCountVo;
        }
        // 新用户订单
        if (rideOrder.getIsNew() == CommonConstant.ONE) {
            rideOrderCountVo.setNewFreeTime(priceRule.getUserRidingMinute());
        }
        MemberCardVo memberCard = null;
        if (allowCoupon) {
            // 检查是否有骑行卡 不指定骑行卡 从用户生效中骑行卡获取
            if(appointMemberCard == null) {
                memberCard = memberCardService.getMemberAvailableRecord(rideOrder.getAreaId(), rideOrder.getMemberId());

            // 指定消耗骑行卡
            }else {
                memberCard = appointMemberCard;
            }
            if(memberCard != null && ObjectUtil.isNotNull(memberCard.getPayStatus()) && memberCard.getPayStatus().equals(CardPayStatusEnum.REFUND.getCode())) memberCard = null;
            if (memberCard != null && memberCard.getCardDayTimes() > 0) {
                // 今日次数已用完
                if (memberCard.getCardDayTimes() <= getTodayCardUserTimes(memberCard)) memberCard = null;
            }
        }
        // 时长计费
        BigDecimal countTimeMoney = BigDecimal.ZERO;

        // 时长普通计费
        if(priceRule.getIsStep() == null || priceRule.getIsStep().equals(CommonConstant.ZERO)) {
            countTimeMoney = OrderPriceUtil.getTimeMoney(rideOrderCountVo, priceRule, memberCard);

        // 时长阶梯计费
        }else {
            List<EbPriceStep>  priceSteps = priceStepService.getAreaPriceStep(priceRule.getAreaId());
            countTimeMoney = OrderPriceUtil.getTimeMoney(rideOrderCountVo, priceRule,  priceSteps, memberCard);
        }
        // 距离收费
        BigDecimal distanceMoney = OrderPriceUtil.getDistanceMoney(rideOrderCountVo, priceRule);
        // 总金额
        BigDecimal money = countTimeMoney.add(distanceMoney);

        // 骑行卡金额优化
        if (money.compareTo(BigDecimal.ZERO) > 0
                && memberCard != null
                && memberCard.getCouponType().equals(CardInfoCouponTypeEnum.MONEY.getCode())) {
            // 最大减免费用 不为空 且大于0
            if(memberCard.getCouponMaxMoney() != null && memberCard.getCouponMaxMoney().compareTo(BigDecimal.ZERO) > 0) {
                //还有剩余余额可以减免
                if(memberCard.getCouponBalanceMoney() != null && memberCard.getCouponBalanceMoney().compareTo(BigDecimal.ZERO) > 0){
                    rideOrderCountVo.setCardRecordId(memberCard.getId());
                    // 总减免费用大于0时，单次减免费用高于余额，按余额减免
                    if(memberCard.getCouponMoney().compareTo(memberCard.getCouponMaxMoney()) > 0){
                        // 在单次减免费用大于总减免费用前提下 骑行金额大于剩余金额 剩余金额减免
                        if(money.compareTo(memberCard.getCouponBalanceMoney()) >= 0) {
                            rideOrderCountVo.setCardFreeMoney(memberCard.getCouponBalanceMoney());

                            // 在单次减免费用大于总减免费用前提下 骑行金额小于剩余金额 骑行金额减免
                        }else{
                            rideOrderCountVo.setCardFreeMoney(money);
                        }
                    }else {
                        rideOrderCountVo.setCardFreeMoney(memberCard.getCouponMoney());
                    }
                    money = money.subtract(rideOrderCountVo.getCardFreeMoney());
                }
            }else {
                rideOrderCountVo.setCardRecordId(memberCard.getId());
                rideOrderCountVo.setCardFreeMoney(memberCard.getCouponMoney());
                money = money.subtract(memberCard.getCouponMoney());
            }

            if (money.compareTo(BigDecimal.ZERO) < 0) money = new BigDecimal(0);
        }
        // 优惠券金额优惠
        if (allowCoupon && money.compareTo(BigDecimal.ZERO) > 0) {
            MemberCouponVo memberCoupon = null;
            // 指定优惠券
            if(appointMemberCoupon != null) {
                memberCoupon = appointMemberCoupon;

            // 获取最优先要使用的优惠券
            }else {
                memberCoupon = memberCouponService.findOneCoupon(rideOrder.getAreaId(), rideOrder.getMemberId(), CouponInfoTypeEnum.RIDE.getCode(), money);
            }
            if (memberCoupon != null) {
                rideOrderCountVo.setCouponId(memberCoupon.getId());
                if (memberCoupon.getCouponType().equals(CouponTypeEnum.MONEY.getCode())) {
                    rideOrderCountVo.setCouponMoney(memberCoupon.getCouponMoney());
                    money = money.subtract(rideOrderCountVo.getCouponMoney());
                } else if (memberCoupon.getCouponType().equals(CouponTypeEnum.RATE.getCode())) {
                    BigDecimal rateMoney = money.multiply(memberCoupon.getCouponRate()).setScale(2, RoundingMode.HALF_UP);
                    rideOrderCountVo.setCouponMoney(money.subtract(rateMoney));
                    money = rateMoney;
                }
                if (money.compareTo(new BigDecimal(0)) < 0) money = new BigDecimal(0);
            }
        }
        // 骑行基础金额
        rideOrderCountVo.setOrderMoney(money);

        // 订单金额
        rideOrderCountVo.setMoney(money);
        return rideOrderCountVo;
    }

    @Override
    public IPage<RideOrderVo> pages(RideOrderDto rideOrderDto) {
        return rideOrderMapper.selectOrderList(Page.of(rideOrderDto.getPageNumber(), rideOrderDto.getPageSize()), rideOrderDto);
    }

    @Override
    public RideOrderVo detail(String orderNo, Integer memberId) {
        RideOrderVo rideOrderVo = rideOrderMapper.selectOrder(orderNo, memberId);

        if(rideOrderVo != null) {
            // 临时代码 先不处理暂停中车辆，只处理骑行中车辆
            if (rideOrderVo.getStatus().equals(RideOrderStatusEnum.RIDING.getCode())) {
                EbRideCommand initCommand = rideCommandService.getCommand(rideOrderVo.getId(), DeviceCommandEnum.CLOSE_LOCK.getType(), RideCommandStatusEnum.INIT, RideCommandTypeEnum.RIDE);
                // initCommand 有可能还没有生成
                // 订单开锁指令大于3000秒仍未响应
                if (initCommand != null && DateUtil.betweenMs(initCommand.getCreateTime(), new Date()) > 3 * 1000  && DateUtil.betweenMs(initCommand.getCreateTime(), new Date()) <= 20 * 1000) {
                    EbDeviceBike deviceBike = deviceBikeService.getById(rideOrderVo.getBikeId());
                    // 如果车辆已关锁
                    if (CommonConstant.ZERO.equals(deviceBike.getLockStatus())) {
                        // 模拟关锁
                        rideCommandService.orderCloseCommand(deviceBike, rideOrderVo, initCommand, "未响应补充关闭订单", UserTypeEnum.MEMBER.getCode());
                        // 重新拉取
                        rideOrderVo = rideOrderMapper.selectOrder(orderNo, memberId);
                    }
                }
            }

            BikeAreaParam bikeAreaParam = agentParamCacheService.getParam(rideOrderVo.getAgentId(), rideOrderVo.getAreaId());
            if (bikeAreaParam != null && bikeAreaParam.getUserRideStopBikeMaxTimesEnabled()) {
                if (bikeAreaParam.getUserRideStopBikeMaxTimes() <= 0) {
                    rideOrderVo.setRemainStopLockTimes(CommonConstant.ZERO);
                } else {
                    Integer orderStopLockTimes = rideCommandService.getCommandCount(rideOrderVo.getId(), DeviceCommandEnum.STOP_LOCK);
                    rideOrderVo.setRemainStopLockTimes(bikeAreaParam.getUserRideStopBikeMaxTimes() - orderStopLockTimes);
                }
            }
        }
        return rideOrderVo;
    }


    @Override
    public void memberOrderEvaluateData(RideOrderForm rideOrderForm) {
        LambdaUpdateWrapper<EbRideOrder> ebRideOrderLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        ebRideOrderLambdaUpdateWrapper.set(EbRideOrder::getEvaluateRate, rideOrderForm.getEvaluateRate());
        ebRideOrderLambdaUpdateWrapper.set(EbRideOrder::getEvaluateRemark, rideOrderForm.getEvaluateRemark());
        ebRideOrderLambdaUpdateWrapper.set(EbRideOrder::getEvaluateImages, rideOrderForm.getEvaluateImages());
        ebRideOrderLambdaUpdateWrapper.eq(EbRideOrder::getId, rideOrderForm.getId());
        this.update(ebRideOrderLambdaUpdateWrapper);
    }

    /**
     * 取消骑行中结算
     */
    @Override
    public void cancelOrderSettleForClose(Integer orderId) {
        rideOrderService.update(new LambdaUpdateWrapper<EbRideOrder>()
            .set(EbRideOrder::getEndLat, null)
            .set(EbRideOrder::getEndLng, null)
            .set(EbRideOrder::getEndStationId, null)
            .set(EbRideOrder::getCloseType, null)
            .set(EbRideOrder::getCloseTime, null)
            .set(EbRideOrder::getHelmetPay, null) // 头盔罚款
            .set(EbRideOrder::getDispatchReduceMoney, null) // 调度减免金额
            .set(EbRideOrder::getDispatchReduceType, null) // 调度减免类型
            .set(EbRideOrder::getDispatchType, null) // 调度类型
            .set(EbRideOrder::getDispatchMoney, null) // 调度实际罚款
            .eq(EbRideOrder::getId, orderId));
    }
    /**
     * 订单结束前结算
     */
    public void orderSettleForClose(EbRideOrder rideOrder, BigDecimal customMoney, Integer userType) {
        redisService.set(BikeConstants.REDIS_LOCK_CMD_RIDE_ORDER_CLOSEING + rideOrder.getId(), 1, 10);

        EbDeviceBike deviceBike = deviceBikeService.getById(rideOrder.getBikeId());

        Date closeTime = new Date();
        EbPriceRule priceRule = priceRuleService.getRule(rideOrder.getAreaId());

        // 调度费检查
        OrderPenaltyVo orderPenalty = getOrderPenalty(rideOrder, deviceBike, priceRule, userType);

        EbMemberInfo memberInfo = memberInfoService.getById(rideOrder.getMemberId());
        // 免费订单不消耗 骑行卡和优惠券
        if((customMoney != null && customMoney.compareTo(BigDecimal.ZERO) == 0) || memberInfo.getLevel() == CommonConstant.TWO) {
            orderPenalty.setAllowCoupon(false);
        }
        RideOrderCountVo rideOrderCountVo = rideOrderService.getOrderCount(rideOrder, closeTime, orderPenalty.getAllowCoupon(), true);

        // 免费骑行，不收取调度费
        if (rideOrderCountVo.getFreeTime() > 0 && priceRule.getIsRidingDispatch() == 0) orderPenalty.setDispatchMoney(BigDecimal.ZERO);

        // 订单原价格
        BigDecimal orderMoney = rideOrderCountVo.getOrderMoney();

        BigDecimal money = orderMoney.add(orderPenalty.getDispatchMoney()).add(orderPenalty.getHelmetPay());

        //免费用户
        Integer closeType = CommonConstant.ONE;
        if (Objects.equals(memberInfo.getLevel(), CommonConstant.TWO)) {
            money = BigDecimal.ZERO;
            closeType = CommonConstant.TWO;
        } else {
            // 自定义订单价格
            if (customMoney != null) {
                money = customMoney;
                closeType = CommonConstant.THREE;
            }
        }
        if(money.compareTo(BigDecimal.ZERO) <= 0){
            orderMoney = BigDecimal.ZERO;
            orderPenalty.setDispatchMoney(BigDecimal.ZERO);
            orderPenalty.setHelmetPay(BigDecimal.ZERO);
        }

        BigDecimal timeMoneyReal = rideOrderCountVo.getBeforeTimeMoney().add(rideOrderCountVo.getOverRideTimeMoney());
        BigDecimal distanceMoneyReal = rideOrderCountVo.getBeforeDistanceMoney().add(rideOrderCountVo.getOverDistanceMoney());

        rideOrderService.update(new LambdaUpdateWrapper<EbRideOrder>()
            .set(EbRideOrder::getEndLat, deviceBike.getLat())
            .set(EbRideOrder::getEndLng, deviceBike.getLng())
            .set(EbRideOrder::getEndStationId, deviceBike.getStationId())
            .set(EbRideOrder::getCloseType, closeType)
            .set(EbRideOrder::getCloseTime, closeTime)
            .set(EbRideOrder::getAllTime, rideOrderCountVo.getAllTime())
            .set(EbRideOrder::getAllDistance, rideOrderCountVo.getAllDistance())
            .set(EbRideOrder::getFreeTime, rideOrderCountVo.getFreeTime())
            .set(EbRideOrder::getNewFreeTime, rideOrderCountVo.getNewFreeTime())
            .set(EbRideOrder::getRideTime, rideOrderCountVo.getRideTime())
            .set(EbRideOrder::getBeforeTime, rideOrderCountVo.getBeforeTime())
            .set(EbRideOrder::getBeforeTimeMoney, rideOrderCountVo.getBeforeTimeMoney())
            .set(EbRideOrder::getBeforeDistance, rideOrderCountVo.getBeforeDistance())
            .set(EbRideOrder::getBeforeDistanceMoney, rideOrderCountVo.getBeforeDistanceMoney())
            .set(EbRideOrder::getOverTime, rideOrderCountVo.getOverTime())
            .set(EbRideOrder::getOverRideTimeMoney, rideOrderCountVo.getOverRideTimeMoney())
            .set(EbRideOrder::getRideDistance, rideOrderCountVo.getRideDistance())
            .set(EbRideOrder::getOverDistance, rideOrderCountVo.getOverDistance())
            .set(EbRideOrder::getOverDistanceMoney, rideOrderCountVo.getOverDistanceMoney())
            .set(EbRideOrder::getTimeMoneyReal, timeMoneyReal)
            .set(EbRideOrder::getDistanceMoneyReal, distanceMoneyReal)
            .set(EbRideOrder::getBeforeMoney, timeMoneyReal.add(distanceMoneyReal))
            .set(EbRideOrder::getCardRecordId, rideOrderCountVo.getCardRecordId())
            .set(EbRideOrder::getCardFreeTime, rideOrderCountVo.getCardFreeTime())
            .set(EbRideOrder::getCardFreeMoney, rideOrderCountVo.getCardFreeMoney()) // 骑行卡优惠金额
            .set(EbRideOrder::getCouponId, rideOrderCountVo.getCouponId())
            .set(EbRideOrder::getCouponMoney, rideOrderCountVo.getCouponMoney()) // 优惠券优惠金额
            .set(EbRideOrder::getOrderMoney, orderMoney)
            .set(EbRideOrder::getHelmetPay, orderPenalty.getHelmetPay()) // 头盔罚款
            .set(EbRideOrder::getDispatchReduceMoney, orderPenalty.getDispatchReduceMoney()) // 调度减免金额
            .set(EbRideOrder::getDispatchReduceType, orderPenalty.getDispatchReduceType()) // 调度减免类型
            .set(EbRideOrder::getDispatchType, orderPenalty.getDispatchType()) // 调度类型
            .set(EbRideOrder::getDispatchMoney, orderPenalty.getDispatchMoney()) // 调度实际罚款
            .set(EbRideOrder::getMoney, money) // 支付金额
            .set(EbRideOrder::getCappingDistance, rideOrderCountVo.getCappingDistance())
            .set(EbRideOrder::getCappingDistanceMoney, rideOrderCountVo.getCappingDistanceMoney())
            .set(EbRideOrder::getCappingTime, rideOrderCountVo.getCappingTime())
            .set(EbRideOrder::getCappingTimeMoney, rideOrderCountVo.getCappingTimeMoney())
            .set(EbRideOrder::getModifyTime, new Date())
            .eq(EbRideOrder::getId, rideOrder.getId()));
    }

    /**
     * 获取订单罚款
     */
    private OrderPenaltyVo getOrderPenalty(EbRideOrder rideOrder, EbDeviceBike deviceBike, EbPriceRule priceRule, Integer userType) {
        OrderPenaltyVo vo = new OrderPenaltyVo();

        BikeAreaParam bikeAreaParam = agentParamCacheService.getParam(rideOrder.getAgentId(), rideOrder.getAreaId());
        Integer dispatchType = null;
        BigDecimal dispatchMoney = new BigDecimal(0);
        BigDecimal dispatchReduceMoney = new BigDecimal(0);
        BigDecimal helmetPay = new BigDecimal(0);
        Integer dispatchReduceType = null;

        // 订单关锁记录
        EbRideClose rideClose = rideCloseService.getByOrderCode(rideOrder.getOrderNo());
        if(rideClose == null) {
            // 头盔检测
            if(!rideHelmetService.checkReturnBikeHelmet(bikeAreaParam, deviceBike, rideOrder)) {
                helmetPay = this.getHelmetPayMoney(userType, priceRule, helmetPay);
            }

            // 服务区检测
            if (deviceBike.getIsInArea().equals(CommonConstant.ZERO)) {
                dispatchType = CommonConstant.TWO;
                // 有调度费
                if (priceRule.getSuperDispatchFee().compareTo(BigDecimal.ZERO) > 0) {
                    dispatchMoney = priceRule.getSuperDispatchFee();
                }
                // 停车点检查
            } else if (deviceBike.getStationId() == null) {
                // 禁停区
                if (deviceBike.getNoparkingId() != null) {
                    dispatchType = CommonConstant.THREE;
                    // 有调度费
                    if (priceRule.getNoparkingDispatchFee().compareTo(BigDecimal.ZERO) > 0) {
                        dispatchMoney = priceRule.getNoparkingDispatchFee();
                    }
                } else {
                    dispatchType = CommonConstant.ONE;
                    // 有调度费
                    if (priceRule.getStationDispatchFee().compareTo(BigDecimal.ZERO) > 0) {
                        // 如果首次站外减免开启
                        if (priceRule.getStationFirstPrevent().equals(CommonConstant.ONE)) {
                            EbRideOrder first = this.getFirstStationDispatch(rideOrder.getMemberId(), rideOrder.getAreaId());
                            if (first != null) {
                                dispatchMoney = priceRule.getStationDispatchFee();
                            } else {
                                dispatchReduceMoney = priceRule.getStationDispatchFee();
                                dispatchReduceType = CommonConstant.ONE;
                            }
                        } else {
                            dispatchMoney = priceRule.getStationDispatchFee();
                        }
                    }
                }

                // rfid停车检查  调度费
            } else if (StrUtil.isBlank(deviceBike.getRfidNo())) {
                EbOperationStation station = operationStationService.getById(deviceBike.getStationId());
                // rfid停车检查
                if (station != null && station.getRfidStopEnabled() != null && station.getRfidStopEnabled() >= CommonConstant.ZERO) {
                    if (bikeAreaParam != null && station.getRfidStopEnabled().equals(CommonConstant.ZERO)) {
                        bikeAreaParam.setUserStopBikeRfidEnabled(false);
                    } else if (bikeAreaParam != null && station.getRfidStopEnabled().equals(CommonConstant.ONE)) {
                        bikeAreaParam.setUserStopBikeRfidEnabled(true);
                    }
                }
                if (bikeAreaParam != null && bikeAreaParam.getUserStopBikeRfidEnabled()) {
                    dispatchType = CommonConstant.ONE;
                    // 有调度费
                    if (priceRule.getIsOpenDispatch().equals(CommonConstant.ONE)) {
                        // 如果首次站外减免开启
                        if (priceRule.getStationFirstPrevent().equals(CommonConstant.ONE)) {
                            EbRideOrder first = this.getFirstStationDispatch(rideOrder.getMemberId(), rideOrder.getAreaId());
                            if (first != null) {
                                dispatchMoney = priceRule.getStationDispatchFee();
                            } else {
                                dispatchReduceMoney = priceRule.getStationDispatchFee();
                                dispatchReduceType = CommonConstant.ONE;
                            }
                        } else {
                            dispatchMoney = priceRule.getStationDispatchFee();
                        }
                    }
                }
            }
        } else {
            dispatchType = rideClose.getDispatchType();
            dispatchReduceMoney = rideClose.getDispatchFreeMoney() == null? BigDecimal.ZERO : rideClose.getDispatchFreeMoney();
            dispatchReduceType = CommonConstant.ONE;
            dispatchMoney = rideClose.getDispatchMoney() == null? BigDecimal.ZERO : rideClose.getDispatchMoney();
            helmetPay = rideClose.getHelmetMoney() == null? BigDecimal.ZERO : rideClose.getHelmetMoney();
        }
        vo.setDispatchType(dispatchType);
        vo.setDispatchReduceMoney(dispatchReduceMoney);
        vo.setDispatchReduceType(dispatchReduceType);
        vo.setDispatchMoney(dispatchMoney);
        vo.setHelmetPay(helmetPay);
        vo.setAllowCoupon(dispatchMoney.compareTo(new BigDecimal(0)) > 0 ? bikeAreaParam.getUserDispatchAllowDiscount() : true);
        return vo;
    }

    /**
     * 订单归还车辆
     */
    @Transactional
    @Override
    public void orderBikeReturn(Integer orderId, boolean payFirstMode, Integer closeUserType) {
        EbRideOrder rideOrder = this.getById(orderId);

        if (!payFirstMode) {

            // 关闭订单骑行距离计算
            rideDistanceService.orderClose(rideOrder.getId(), rideOrder.getBikeId());

            rideOrderService.update(new LambdaUpdateWrapper<EbRideOrder>()
                .set(EbRideOrder::getStatus, RideOrderStatusEnum.CONFIRM.getCode())
                .eq(EbRideOrder::getId, orderId));
        }

        if (rideOrder.getCardRecordId() != null) {
            memberCardService.costTimes(rideOrder.getCardRecordId(), rideOrder.getCardFreeMoney());
        }

        if (rideOrder.getCouponId() != null) {
            memberCouponService.useCoupon(rideOrder.getCouponId());
        }

        // 更新车辆信息 车辆设置为空闲
        deviceBikeService.update(new LambdaUpdateWrapper<EbDeviceBike>()
                .set(EbDeviceBike::getUseStatus, DeviceBikeUseStatusEnum.IDLE.getCode())
                .set(EbDeviceBike::getUsePerson, null)
                .set(EbDeviceBike::getLastRideTime, new Date())
                .eq(EbDeviceBike::getId, rideOrder.getBikeId()));

        try {
            JSONObject eventData = new JSONObject();
            eventData.put("bikeId", rideOrder.getBikeId());
            eventData.put("orderId", rideOrder.getId());
            eventData.put("agentId", rideOrder.getAgentId());
            eventData.put("areaId", rideOrder.getAreaId());
            eventData.put("memberId", rideOrder.getMemberId());
            eventData.put("closeUserType", closeUserType);
            eventService.sendEvent(BikeEventCode.RIDE_ORDER_BIKE_RETURN_SUCCESS,
                    eventData,
                    "USER_rideOrderService_orderBikeReturnSuccess");
        } catch (Exception e) {
            log.error("BikeEventCode RIDE_ORDER_BIKE_RETURN_SUCCESS rabbitmq error:{}", e.getMessage());
        }
    }

    private BigDecimal getHelmetPayMoney(Integer userType, EbPriceRule priceRule, BigDecimal helmetPay) {
        if(userType == null || userType.equals(UserTypeEnum.MEMBER.getCode())) {
            if (priceRule.getIsNoHelmet() != null && priceRule.getIsNoHelmet().equals(CommonConstant.ONE)) {
                helmetPay = priceRule.getHelmetPay();
            }
        }else {
            if (priceRule.getIsNoHelmet() != null && priceRule.getIsNoHelmet().equals(CommonConstant.ONE)) {
                helmetPay = priceRule.getSysHelmetPay();
            }
        }
        return helmetPay;
    }

    @Override
    public EbRideOrder getFirstStationDispatch(Integer memberId, Integer areaId) {
        return this.getOne(new LambdaQueryWrapper<EbRideOrder>()
                .eq(EbRideOrder::getMemberId, memberId)
                .eq(EbRideOrder::getAreaId, areaId)
                .eq(EbRideOrder::getDispatchType, CommonConstant.ONE)
                .last("limit 1"));
    }

    @Override
    public void freeOrderAutoPay(EbRideOrder rideOrder, Integer userType) {
        // 订单完成
        this.orderPaid(rideOrder.getId(), new BigDecimal(0), new BigDecimal(0), userType);

        // 发送通知
        messageInfoService.addSys(rideOrder.getMemberId(), MessageChannelEnum.SYS,
            "尊敬的用户，您于 " + DateUtil.now() + " 结束订单成功，本次骑行免费 ，感谢您的支持与信任！",
            null, MessageBusinessTypeEnum.ORDER, rideOrder.getId());
    }
    /**
     * 待确认订单自动支付逻辑，优先余额，其次支付分
     * @param orderId
     */
    @Override
    public void confirmAutoPay(Integer orderId, Integer userType) {
        EbRideOrder rideOrder = this.getById(orderId);
        if (!rideOrder.getStatus().equals(RideOrderStatusEnum.CONFIRM.getCode())) return;
        this.autoPay(rideOrder, userType);
    }
    /**
     * 自动支付逻辑，优先余额，其次支付分
     */
    @Override
    public boolean autoPay(EbRideOrder rideOrder, Integer userType) {
        AgentInfo agentInfo = LocalMapUtil.getAgentInfo();
        BikeParam param = agentParamCacheService.getParam(agentInfo.getId());
        // 如果需支付费用是0
        if (rideOrder.getMoney().compareTo(new BigDecimal(0)) <= 0) {
            if(param != null && param.getRideOrderWxPayScore()){
                // C1：取消用户支付分订单
                preOrderService.cancelOrder(rideOrder.getMemberId());
            }
            this.freeOrderAutoPay(rideOrder, userType);
            return true;
        }

        // 尝试钱包支付
        boolean res = memberWalletService.payForRideOrder(rideOrder);

        // 如果支持支付分
        if(param != null && param.getRideOrderWxPayScore()){
            if(res) {
                // C1：取消用户支付分订单
                preOrderService.cancelOrder(rideOrder.getMemberId());
            } else {
                // 支付分只允许支付骑行费用
                if (rideOrder.getOrderMoney().compareTo(new BigDecimal(0)) <= 0) {
                    // C2：取消用户支付分订单
                    preOrderService.cancelOrder(rideOrder.getMemberId());
                } else {
                    // 订单罚款金额
                    BigDecimal penaltyMoney = rideOrder.getDispatchMoney().add(rideOrder.getHelmetPay());
                    // 创建独立罚单
                    if (penaltyMoney.compareTo(BigDecimal.ZERO) > 0) {
                        this.update(new LambdaUpdateWrapper<EbRideOrder>()
                            .set(EbRideOrder::getPenaltyPayStatus, RideOrderPenaltyPayStatusEnum.WAIT_PAY_RIDE.getCode())
                            .eq(EbRideOrder::getId, rideOrder.getId()));
                        ridePenaltyService.addByOrder(rideOrder, penaltyMoney);
                    }
                    preOrderService.payForRideOrder(rideOrder);
                }
            }
        }
        return res;
    }

    @Override
    public void orderPaid(Integer orderId, BigDecimal payChargeMoney, BigDecimal payGiftMoney, Integer userType) {
        EbRideOrder rideOrder = this.getById(orderId);

        LambdaUpdateWrapper<EbRideOrder> update = new LambdaUpdateWrapper<>();
        update.set(EbRideOrder::getPayChargeMoney, payChargeMoney);
        update.set(EbRideOrder::getPayGiftMoney, payGiftMoney);
        update.set(EbRideOrder::getPayTime, new Date());
        if (rideOrder.getPenaltyPayStatus().equals(RideOrderPenaltyPayStatusEnum.ONE_PAY.getCode())) {
            // 一并支付，直接完成
            update.set(EbRideOrder::getStatus, RideOrderStatusEnum.COMPLETE.getCode());
            this.sendNotice(LocalMapUtil.getAgentInfo(), rideOrder);
        } else if (rideOrder.getPenaltyPayStatus().equals(RideOrderPenaltyPayStatusEnum.WAIT_PAY_RIDE.getCode())) {
            // 骑行费用已支付，仅修改罚款状态，此情况一般只有微信支付分支付成功才发生
            // 客服结束骑行中订单时，可能会遇到调度费、头盔金额设置成0的情况，此处需再次判断一次是否需要支付调度费。
            BigDecimal penaltyMoney = rideOrder.getDispatchMoney().add(rideOrder.getHelmetPay()); // 订单罚款金额
            if (penaltyMoney.compareTo(BigDecimal.ZERO) > 0) {
                update.set(EbRideOrder::getPenaltyPayStatus, RideOrderPenaltyPayStatusEnum.WAIT_PAY_PENALTY.getCode());
                // 订单状态依然是待支付
            } else {
                update.set(EbRideOrder::getPenaltyPayStatus, RideOrderPenaltyPayStatusEnum.ONE_PAY.getCode());
                update.set(EbRideOrder::getStatus, RideOrderStatusEnum.COMPLETE.getCode());
                this.sendNotice(LocalMapUtil.getAgentInfo(), rideOrder);
            }
        }
        update.eq(EbRideOrder::getId, orderId);
        // 更新订单信息
        this.update(update);

        // 关闭订单骑行距离计算
        rideDistanceService.orderClose(rideOrder.getId(), rideOrder.getBikeId());

        // 如果是骑行中订单支付完成
        if (rideOrder.getStatus().equals(RideOrderStatusEnum.RIDING.getCode()) || rideOrder.getStatus().equals(RideOrderStatusEnum.PAUSE.getCode())) {
            try {

                // 自行关锁，关锁失败也无所谓，结束订单
                SendBikeCommandForm commandForm = new SendBikeCommandForm()
                    .setAgentId(LocalMapUtil.getAgentInfo().getId())
                    .setBikeNo(rideOrder.getBikeNo())
                    .setCommand(DeviceCommandEnum.CLOSE_LOCK.getType())
                    .setUserId(0)
                    .setUserName("先支付后锁车")
                    .setUserType(UserTypeEnum.SYS.getCode())
                    .setIsSync(CommonConstant.ZERO);
                iotBikeClient.sendBikeCommand(commandForm);
            } catch (Exception e) {
                log.error("iotBikeClient.sendBikeCommand error", e);
            }

            rideOrderService.orderBikeReturn(rideOrder.getId(), true, userType);
        }
    }

    /**
     * 订单罚款缴纳
     * @param orderId
     */
    @Override
    public void orderPenaltyPaid(Integer orderId) {
        LambdaUpdateWrapper<EbRideOrder> update = new LambdaUpdateWrapper<>();
        update.set(EbRideOrder::getPenaltyPayStatus, CommonConstant.FOUR);
        update.set(EbRideOrder::getStatus, RideOrderStatusEnum.COMPLETE.getCode());
        update.eq(EbRideOrder::getId, orderId);
        // 更新订单信息
        this.update(update);
        EbRideOrder rideOrder = this.getById(orderId);
        this.sendNotice(LocalMapUtil.getAgentInfo(), rideOrder);
    }


    private void sendNotice(AgentInfo agentInfo, EbRideOrder order) {
        EbRemindRule notifyRule = remindRuleService.getNotifyRule(agentInfo.getId(), CommonConstant.ONE);
        if (notifyRule == null) {
            return;
        }

        EbMemberInfo memberInfo = memberInfoService.getById(order.getMemberId());

        // 发送微信小程序消息
        if (notifyRule.getPushChannel().contains(CommonConstant.THREE.toString()) && notifyRule.getWxMiniTemplete() != null) {
            if(StrUtil.isNotBlank(memberInfo.getOpenId())) {
                MessageAddForm messageAddForm = new MessageAddForm();
                messageAddForm.setMemberId(memberInfo.getId());
                messageAddForm.setOpenId(memberInfo.getOpenId());
                messageAddForm.setWxTemplateId(notifyRule.getWxMiniTemplete());
                messageAddForm.setOrderNo(order.getOrderNo());
                messageAddForm.setRentTime(DateUtil.formatDateTime(order.getPayTime()));
                messageAddForm.setUsedTime(DateUtil.between(order.getOpenTime(),order.getCloseTime(), DateUnit.MINUTE)+"分钟");
                messageAddForm.setAmount(order.getMoney()+"元");
                commonClient.sendOrderCompleteWx(agentInfo.getId(), messageAddForm);
            }
        }

        // 发送用户消息
        if (notifyRule.getPushChannel().contains(CommonConstant.TWO.toString())) {
            MessageAddForm messageAddForm = new MessageAddForm();
            messageAddForm.setMemberId(memberInfo.getId());
            messageAddForm.setChannel(MessageChannelEnum.SYS);
            messageAddForm.setContent("骑行订单已完成");
            messageAddForm.setBusinessId(order.getId());
            messageAddForm.setBusinessType(MessageBusinessTypeEnum.ORDER);
            messageAddForm.setImage(null);
            commonClient.sendOrderComplete(agentInfo.getId(), messageAddForm);
        }

    }

    @Override
    public EbRideOrder getUserConfirmOrder(Integer memberId) {
        return this.getOne(new LambdaQueryWrapper<EbRideOrder>().eq(EbRideOrder::getMemberId, memberId)
                .eq(EbRideOrder::getStatus, RideOrderStatusEnum.CONFIRM.getCode())
                .orderByDesc(EbRideOrder::getId).last("limit 1"));
    }

    @Override
    public List<EbRideOrder> listUnPayOrder(int seconds) {
        Date nowDate = new Date();
        List<EbRideOrder> orders = this.list(new LambdaQueryWrapper<EbRideOrder>()
                .eq(EbRideOrder::getStatus, RideOrderStatusEnum.CONFIRM.getCode()));
        List<EbRideOrder> result = new ArrayList<>();
        for (EbRideOrder order : orders) {
            long diffSeconds = DateUtil.between(order.getCloseTime(), nowDate, DateUnit.SECOND);
            //未支付时间达标，并设置上限，避免重复查询问题.
            if (diffSeconds > seconds && diffSeconds < 2*seconds) {
                result.add(order);
            }
        }
        return result;
    }

    @Override
    @Transactional
    public void rideRefund(RideRefundForm form) {
        String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:REFUND:ORDER:" + form.getRideOrderId();
        Assert.isTrue(redisService.setNx(key, form.getRideOrderId(), 5), "该订单正在退款中,请稍等....");

        try {
            // 订单信息
            EbRideOrder ebRideOrder = this.getById(form.getRideOrderId());
            Assert.notNull(ebRideOrder, "订单不存在!");
            Assert.isTrue(ebRideOrder.getStatus().equals(RideOrderStatusEnum.COMPLETE.getCode()), "该订单不支持退款!");
            if(form.getRefundType().equals(RefundTypeEnum.ORDER.getCode())){
                BigDecimal refundOrderMoney = (ObjectUtil.isNull(ebRideOrder.getRefundOrderMoney()) ? BigDecimal.ZERO : ebRideOrder.getRefundOrderMoney())
                        .add(form.getRefundMoney());
                if(refundOrderMoney.compareTo(ebRideOrder.getOrderMoney().add(ebRideOrder.getHelmetPay())) > 0){
                    throw new BadResponseException("退款骑行费用超出!");
                }
            }
            if(form.getRefundType().equals(RefundTypeEnum.DISPATCH.getCode())){
                BigDecimal refundDispatchMoney = (ObjectUtil.isNull(ebRideOrder.getRefundDispatchMoney()) ? BigDecimal.ZERO : ebRideOrder.getRefundDispatchMoney())
                        .add(form.getRefundMoney());
                if(refundDispatchMoney.compareTo(ebRideOrder.getDispatchMoney()) > 0){
                    throw new BadResponseException("退款调度费用超出!");
                }
            }
            if(form.getRefundType().equals(RefundTypeEnum.HELMET.getCode())){
                BigDecimal refundHelmetMoney = (ObjectUtil.isNull(ebRideOrder.getRefundHelmetMoney()) ? BigDecimal.ZERO : ebRideOrder.getRefundHelmetMoney())
                        .add(form.getRefundMoney());
                if(refundHelmetMoney.compareTo(ebRideOrder.getHelmetPay()) > 0){
                    throw new BadResponseException("退款头盔赔偿费用超出!");
                }
            }
            // 支付记录
            EbMemberPay ebMemberPay = memberPayService.getOne(new LambdaQueryWrapper<EbMemberPay>()
                    .eq(EbMemberPay::getBusinessType, MemberPayBusinessTypeEnum.RIDE_ORDER_PAY.getCode())
                    .eq(EbMemberPay::getBusinessId, form.getRideOrderId())
                    .eq(EbMemberPay::getStatus,MemberPayStatusEnum.PAID.getCode())
                    .last("limit 0,1"));
            Assert.notNull(ebMemberPay, "没有获取到支付记录!");
            Assert.isTrue(ebMemberPay.getMoney().compareTo(BigDecimal.ZERO) > 0, "金额不支持退款!");

            // 业务数据
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("refundType",form.getRefundType());

            // 退款金额不能超出
            BigDecimal sumRefundMoney = form.getRefundMoney().add(ObjectUtil.isNull(ebMemberPay.getRefundMoney())?BigDecimal.ZERO : ebMemberPay.getRefundMoney());
            Assert.isTrue(sumRefundMoney.compareTo(ebRideOrder.getMoney()) <= 0,"退款金额超出!");
            AgentInfo agentInfo = LocalMapUtil.getAgentInfo();
            String notifyUrl = "http://"+ agentInfo.getDomain()+ "/api/v1/bikeuser/notify";
            if (ebMemberPay.getPayChannel().equals(PayChannelEnum.WALLET.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),ebMemberPay.getMemberId(), ebRideOrder.getId(), ebMemberPay.getId(), ebMemberPay.getFeeRatio(), form.getRefundMoney(), RefundBusinessTypeEnum.ORDER, RefundChannelEnum.MONEY, form.getRefundReason(),form.getLoginUser(),jsonObject.toJSONString());
                // 退款赠送金额
                BigDecimal refundPayGiftMoney = BigDecimal.ZERO;
                if(ebRideOrder.getPayGiftMoney() != null && ebRideOrder.getPayGiftMoney().compareTo(BigDecimal.ZERO) > 0
                        && (ebRideOrder.getRefundPayGiftMoney() == null? BigDecimal.ZERO : ebRideOrder.getRefundPayGiftMoney())
                        .compareTo(ebRideOrder.getPayGiftMoney()) < 0) {
                    BigDecimal sumRefundPayGiftMoney = (ebRideOrder.getRefundPayGiftMoney() == null? BigDecimal.ZERO : ebRideOrder.getRefundPayGiftMoney()).add(form.getRefundMoney());
                    // 赠送金额退款超出支付赠送金额
                    if(sumRefundPayGiftMoney.compareTo(ebRideOrder.getPayGiftMoney()) > 0) {
                        refundPayGiftMoney = ebRideOrder.getPayGiftMoney().subtract((ebRideOrder.getRefundPayGiftMoney() == null? BigDecimal.ZERO : ebRideOrder.getRefundPayGiftMoney()));
                    } else {
                        refundPayGiftMoney = form.getRefundMoney();
                    }

                }

                // 退款充值金额
                BigDecimal refundPayChargeMoney = BigDecimal.ZERO;
                if(refundPayGiftMoney.compareTo(BigDecimal.ZERO) <= 0) {
                    refundPayChargeMoney = form.getRefundMoney();
                } else {
                    refundPayChargeMoney = form.getRefundMoney().subtract(refundPayGiftMoney);
                }
                if(refundPayChargeMoney.compareTo(BigDecimal.ZERO) < 0) {
                    refundPayChargeMoney = BigDecimal.ZERO;
                }

                memberWalletService.refundMoney(ebRideOrder.getAreaId(),ebMemberPay.getMemberId(), MemberMoneyBusinessTypeEnum.RIDE_ORDER_REFUND, ebRideOrder.getId(), refundPayChargeMoney, refundPayGiftMoney);
                refundInfoService.refundSuccess(ebRefundInfo.getRefundNo(), null);
            } else if (ebMemberPay.getPayChannel().equals(PayChannelEnum.WXPAY.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),
                        ebMemberPay.getMemberId(),
                        ebRideOrder.getId(),
                        ebMemberPay.getId(),
                        ebMemberPay.getFeeRatio(),
                        form.getRefundMoney(),
                        RefundBusinessTypeEnum.ORDER,
                        RefundChannelEnum.WX,
                        form.getRefundReason(),
                        form.getLoginUser(),
                        jsonObject.toJSONString());
                EbMemberInfo ebMemberInfo = memberInfoService.getById(ebRideOrder.getMemberId());
                EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
                if (info.getPayAccountId() != null) {
                    EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), ebRideOrder.getMemberId());
                    if (payAccount != null) {
                        BikeRefundForm refundForm = new BikeRefundForm();
                        refundForm.setBusinessType(RefundBusinessTypeEnum.ORDER);
                        refundForm.setMemberPayId(ebMemberPay.getId());
                        refundForm.setMoney(ebRefundInfo.getMoney());
                        refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                        refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                        refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                        AjaxResult result = payClient.refund(ebMemberPay.getAgentId(), refundForm);
                        Assert.isTrue(result.isSuccess(), result.getMessage());
                        return;
                    }
                }
                try {
                    WxPayUtil.refund(
                            agentInfo.getWxMchId(),
                            ebRefundInfo.getRefundNo(),
                            ebMemberPay.getPayNo(),
                            "骑行订单退款",
                            ebRefundInfo.getMoney(),
                            ebMemberPay.getMoney(),
                            agentInfo.getWxKeyPath(),
                            agentInfo.getWxCertPath(),
                            notifyUrl + "/wx/refund/" + LocalMapUtil.getAgentInfo().getId());
                } catch (Exception ex) {
                    log.error("微信退款失败", ex);
                    throw new BadResponseException("微信退款失败:" + ex.getMessage());
                }
            } else if (ebMemberPay.getPayChannel().equals(PayChannelEnum.WXPAYSCORE.getCode())) {
                String url = "https://"+ agentInfo.getDomain()+ "/api/v1/bikeuser/notify";
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),
                        ebMemberPay.getMemberId(),
                        ebRideOrder.getId(), ebMemberPay.getId(), ebMemberPay.getFeeRatio(),
                        form.getRefundMoney(),
                        RefundBusinessTypeEnum.ORDER,
                        RefundChannelEnum.WXPAYSCORE,
                        form.getRefundReason(),
                        form.getLoginUser(),
                        jsonObject.toJSONString());
                try {
                    //支付分退款要用微信支付订单号
                    WxPayUtil.refundPayScore(
                            agentInfo.getWxMchId(),
                            ebRefundInfo.getRefundNo(),
                            ebMemberPay.getChannelNo(),
                            "骑行订单退款",
                            ebRefundInfo.getMoney(),
                            ebMemberPay.getMoney(),
                            agentInfo.getWxKeyPath(),
                            agentInfo.getWxCertPath(),
                            url + "/wx/pay/score/refund/" + LocalMapUtil.getAgentInfo().getId());
                } catch (Exception ex) {
                    log.error("微信支付分退款失败", ex);
                    throw new BadResponseException("微信支付分退款失败:" + ex.getMessage());
                }
            } else if (ebMemberPay.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),ebMemberPay.getMemberId(), ebRideOrder.getId(), ebMemberPay.getId(), ebMemberPay.getFeeRatio(), form.getRefundMoney(), RefundBusinessTypeEnum.ORDER, RefundChannelEnum.ALI, form.getRefundReason(),form.getLoginUser(),jsonObject.toJSONString());
                EbMemberInfo ebMemberInfo = memberInfoService.getById(ebRideOrder.getMemberId());
                EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
                if (info.getPayAccountId() != null) {
                    EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), ebRideOrder.getMemberId());
                    if (payAccount != null) {
                        BikeRefundForm refundForm = new BikeRefundForm();
                        refundForm.setBusinessType(RefundBusinessTypeEnum.ORDER);
                        refundForm.setMemberPayId(ebMemberPay.getId());
                        refundForm.setMoney(ebRefundInfo.getMoney());
                        refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                        refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                        refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                        AjaxResult result = payClient.refund(ebMemberPay.getAgentId(), refundForm);
                        Assert.isTrue(result.isSuccess(), result.getMessage());
                        return;
                    }
                }
                try {
                    Map<String, String> res = AliPayUtil.getTradeRefundRequestParam(
                            agentInfo.getAliMiniAppid(),
                            ebMemberInfo.getAlipayUserId(),
                            ebMemberInfo.getAlipayOpenId(),
                            "骑行订单退款",
                            ebMemberPay.getPayNo(),
                            ebRefundInfo.getRefundNo(),
                            ebRefundInfo.getMoney(),
                            agentInfo.getAliPayPrivateKey(),
                            agentInfo.getAliPayCertPath(),
                            agentInfo.getAliPayPublicCertPath(),
                            agentInfo.getAliPayRootCertPath());
                    ebRefundInfo.setChannelNo(res.get("trade_no"));
                    refundInfoService.refundSuccess(ebRefundInfo.getRefundNo(), null);
                } catch (Exception ex) {
                    log.error("支付宝退款失败", ex);
                    throw new BadResponseException("支付宝退款失败:" + ex.getMessage());
                }
            }
        }catch (Exception ex){
            redisService.del(key);
            throw new BadResponseException(ex.getMessage());
        }
    }

    @Override
    @Transactional
    public void rideRefundSuccess(EbRefundInfo refundInfo) {
        EbRideOrder ebRideOrder = this.getById(refundInfo.getBusinessId());
        Assert.notNull(ebRideOrder,"订单记录不存在:" + refundInfo.getBusinessId());

        // 退款类型
        JSONObject jsonObject = JSONObject.parseObject(refundInfo.getData());
        Integer refundType = jsonObject.getInteger("refundType");
        Assert.notNull(refundType,"识别不到退款类型");

        // 有赠送金额，优先退赠送金额
        BigDecimal refundPayGiftMoney = (ObjectUtil.isNull(ebRideOrder.getRefundPayGiftMoney()) ? BigDecimal.ZERO : ebRideOrder.getRefundPayGiftMoney()).add(refundInfo.getMoney());
        // 超出赠送付款金额部分
        BigDecimal overRefundMoney = BigDecimal.ZERO;
        if(refundPayGiftMoney.compareTo(ebRideOrder.getPayGiftMoney()) > 0){
            overRefundMoney = refundPayGiftMoney.subtract(ebRideOrder.getPayGiftMoney());
            refundPayGiftMoney = ebRideOrder.getPayGiftMoney();
        }
        // 有充值金额，优先退充值金额
        BigDecimal refundPayChargeMoney = BigDecimal.ZERO;
        if(overRefundMoney.compareTo(BigDecimal.ZERO) > 0){
            refundPayChargeMoney = ( ObjectUtil.isNull(ebRideOrder.getRefundPayChargeMoney()) ? BigDecimal.ZERO : ebRideOrder.getRefundPayChargeMoney()).add(overRefundMoney);
        }
        // 订单、调度的费用
        BigDecimal refundOrderMoney = (ObjectUtil.isNull(ebRideOrder.getRefundOrderMoney()) ? BigDecimal.ZERO : ebRideOrder.getRefundOrderMoney());
        if(refundType.equals(RefundTypeEnum.ORDER.getCode())){
            refundOrderMoney = refundOrderMoney.add(refundInfo.getMoney());
        }
        BigDecimal refundDispatchMoney = (ObjectUtil.isNull(ebRideOrder.getRefundDispatchMoney()) ? BigDecimal.ZERO : ebRideOrder.getRefundDispatchMoney());
        if(refundType.equals(RefundTypeEnum.DISPATCH.getCode())){
            refundDispatchMoney = refundDispatchMoney.add(refundInfo.getMoney());
        }
        BigDecimal refundHelmetMoney = (ObjectUtil.isNull(ebRideOrder.getRefundHelmetMoney()) ? BigDecimal.ZERO : ebRideOrder.getRefundHelmetMoney());
        if(refundType.equals(RefundTypeEnum.HELMET.getCode())){
            refundHelmetMoney = refundHelmetMoney.add(refundInfo.getMoney());
        }

        BigDecimal refundMoney = refundOrderMoney.add(refundDispatchMoney).add(refundHelmetMoney);
        this.update(new LambdaUpdateWrapper<EbRideOrder>()
                .set(refundMoney.compareTo(ebRideOrder.getMoney()) >= 0, EbRideOrder::getStatus, RideOrderStatusEnum.REFUND.getCode())
                .set(EbRideOrder:: getRefundPayChargeMoney, refundPayChargeMoney)
                .set(EbRideOrder::getRefundPayGiftMoney, refundPayGiftMoney)
                .set(EbRideOrder::getRefundOrderMoney, refundOrderMoney)
                .set(EbRideOrder::getRefundDispatchMoney, refundDispatchMoney)
                .set(EbRideOrder::getRefundHelmetMoney, refundHelmetMoney)
                .set(EbRideOrder::getRefundMoney, refundMoney)
                .eq(EbRideOrder::getId,ebRideOrder.getId()));
    }

    private void noInStopAreaSendVoice(Integer agentId, String bikeNo, String sysName) {
        try {
            SendBikeCommandForm commandForm = new SendBikeCommandForm()
                    .setCommand(DeviceCommandEnum.RETURN_FAIL_VOICE.getType())
                    .setAgentId(agentId)
                    .setBikeNo(bikeNo)
                    .setUserId(0)
                    .setUserName(sysName)
                    .setUserType(UserTypeEnum.SYS.getCode());
            iotBikeClient.sendBikeCommand(commandForm);
        }catch (Exception ex) {
            log.info("发送语音指令:{}", ex.getMessage());
        }
    }
}
